<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
	<id>http://brain.fuw.edu.pl/edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gbernatowicz</id>
	<title>Brain-wiki - Wkład użytkownika [pl]</title>
	<link rel="self" type="application/atom+xml" href="http://brain.fuw.edu.pl/edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gbernatowicz"/>
	<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php/Specjalna:Wk%C5%82ad/Gbernatowicz"/>
	<updated>2026-04-08T05:52:16Z</updated>
	<subtitle>Wkład użytkownika</subtitle>
	<generator>MediaWiki 1.34.1</generator>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:GSR.pdf&amp;diff=8037</id>
		<title>Plik:GSR.pdf</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:GSR.pdf&amp;diff=8037"/>
		<updated>2019-05-22T09:21:00Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_8&amp;diff=8036</id>
		<title>Pracownia Sygnałów Biologicznych/Zajecia 8</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_8&amp;diff=8036"/>
		<updated>2019-05-22T09:19:08Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Wstęp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;b&amp;gt;Reakcja skórno-galwaniczna&amp;lt;/b&amp;gt;&lt;br /&gt;
==Wstęp==&lt;br /&gt;
&lt;br /&gt;
Prezentacja: [[Media:GSR.pdf]]&lt;br /&gt;
&lt;br /&gt;
Reakcja skórno-galwaniczna (ang. ''galvanic skin response'' &amp;amp;mdash; GSR), nazywana czasami reakcją elektrodermalną, reakcją elektryczną skóry, reakcją psychogalwaniczną, jest zmianą właściwości elektrycznych skóry pod wpływem stanu psychologicznego. Wielkością mierzoną jest oporność skóry lub odwrotność oporności, czyli przewodnictwo. Z definicji oporu elektrycznego, opór (''R'') jest równy stosunkowi napięcia (''V'') do prądu przepływającego przez opór: ''R'' = ''V''/''I''. &lt;br /&gt;
Wzmacniacz podaje stałe napięcie pomiędzy elektrodami i mierzy natężenie przepływającego prądu elektrycznego. Na podstawie zmian natężenia prądu, wyznaczamy zmiany w przewodnictwie skóry. W zapisie przewodnictwa skóry możemy wyróżnić składową stałą (tzw. ''baseline level'') oraz składową zmienną, reagującą na różne rodzaje bodźców zewnętrznych. Składową zmienną nazywa się czasem reakcją GSR i my też będziemy stosować od tej pory to pojęcie. Przykład reakcji GSR jest pokazany na&lt;br /&gt;
&amp;lt;xr id=&amp;quot;fig:GSR&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;&lt;br /&gt;
[[Plik:Gsr.svg|250px|thumb|right|&amp;lt;figure id=&amp;quot;fig:GSR&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt; Reakcja skórno-galwaniczna w sygnale 60 s. Sygnał był mierzony pomiędzy palcem środkowym i wskazującym.]]&lt;br /&gt;
Również przy braku bodźców zewnętrznych obserwuje się spontaniczne reakcje GSR występujące z typową częstością 1-3/minutę. Parametrami do opisu reakcji GSR są:&lt;br /&gt;
* Amplituda: różnica pomiędzy składową stałą a wartością GSR w maksimum odpowiedzi&lt;br /&gt;
* Opóźnienie (latencja): czas pomiędzy bodźcem a początkiem odpowiedzi. Typowe wartości: 3 sekundy lub mniej.&lt;br /&gt;
* Czas narastania: czas pomiędzy początkiem odpowiedzi GSR a jej maksimum. Typowe wartości: 1-3 sekundy.&lt;br /&gt;
* Czas połowicznego zaniku: czas pomiędzy maksimum odpowiedzi GSR i punktem, w którym wartość odpowiedzi malej o połowę. Typowe wartości: 2-10 sekund.&lt;br /&gt;
&lt;br /&gt;
Najbardziej uznany model reakcji GSR zakłada, że wzrost przewodnictwa skóry następuje w wyniku wydzielania potu i wypełniania duktów potowych w skórze. Przewodnictwo wraca do poziomu odniesienia, gdy płyn wydzielony na powierzchnię skóry jest z powrotem wchłonięty przez gruczoły potowe. W modelu tym, dukty potowe odgrywają rolę zmiennych oporników. Ich opór maleje wraz z wypełnieniem. Amplituda GSR zależy od ilości potu dostarczonego do duktów oraz od liczby pobudzonych gruczołów potowych. Np. w skórze dłoni występuje ponad 2000 gruczołów potowych w jednym cm&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Aktywacja kanałów potowych jest kontrolowana przez część współczulną autonomicznego układu nerwowego. Gruczoły potowe dostają cholinergiczne wejścia, które zmieniają napięcie błonowe komórek i regulują ich aktywność. W związku z elektryczną naturą procesów kontroli i działania gruczołów potowych, ich funkcjonowanie może być rejestrowane w postaci potencjałów elektrycznych, podobnie jak zapisy EKG czy EMG.&lt;br /&gt;
&lt;br /&gt;
==Eksperymenty Junga i Mathisona==&lt;br /&gt;
Pierwsze opisy zastosowania aparatury GSR w psychoanalizie pojawiły się w książce Carla Gustava Junga, dotyczącej analizy słów. Osoba badana podłączona była do aparatury mierzącej zmiany przewodnictwa skóry, poprzez elektrody umieszczone na dłoni. Słowa z listy były czytane na głos osobie badanej. Jeśli słowo zawierało ładunek emocjonalny, powodowało ono zmianę przewodnictwa skóry i wychylenie się igły galwanometru. Wszystkie słowa które powodowały odpowiedź odbiegającą znacznie od normy były wskazaniem na możliwe obszary konfliktu wewnętrznego u pacjenta. Jung wykorzystywał reakcje GSR jako metodę dodatkową, wspomagającą jego własne obserwacje dotyczące źródeł konfliktów wewnętrznych u pacjentów.&lt;br /&gt;
Konstrukcja przenośnych wzmacniaczy do GSR spowodowała wzrost zainteresowania tą metodą i jej wykorzystanie jako &amp;amp;bdquo;detektor kłamstw&amp;amp;rdquo;. Podstawą ich działania jest założenie, ze odpowiedź na pytanie niezgodnie z prawdą powoduje wewnętrzny konflikt i reakcje układu autonomicznego, która nie podlega kontroli świadomości. W praktyce, w sądownictwie, badanie detektorem kłamstw nie jest uznawane za dowód. Wykorzystując detektor kłamstw, Volney Mathison zauważył, że niektóre wspomnienia lub zmiany nastroju powodują znaczną reakcje GSR. Opracował on listę słów używaną w połączeniu z pomiarem GSR. Przy niektórych słowach pojawiała się bardzo silna reakcja GSR, która wskazywała, że dane słowo jest powiązane z silnymi emocjami mającymi swoje korzenie w podświadomości. Najczęściej, badany zupełnie nie zdawał sobie sprawy, że wywołał tak silną reakcję w układzie pomiarowym.&lt;br /&gt;
&lt;br /&gt;
==Biofeedback==&lt;br /&gt;
Biofeedback (biologiczne sprzężenie zwrotne) jest techniką samoregulacji. Na podstawie pomiaru stanu fizjologicznego osoby badanej i dostarczania mu zwrotnej informacji o jego zmianach, osoba badane może nauczyć się świadomie modyfikować funkcje, które normalnie nie są kontrolowane świadomie. Zastosowanie pomiaru przewodnictwa skóry w biofeedbacku opiera się na następujących obserwacjach:&lt;br /&gt;
* Niski poziom pobudzenia kory mózgowej jest potrzebny do odczuwania stanu relaksu, w stanie hipnozy oraz do lepszego odczuwania swojej nieświadomości.&lt;br /&gt;
* Wysoki poziom pobudzenia kory mózgowej zapewnia szybszy refleks, koncentrację, zdolność szybszego czytania i lepszego zapamiętywania.&lt;br /&gt;
* Poziom pobudzenia kory mózgowej i przewodnictwo skóry są ze sobą związane. Pobudzenie kory mózgowej jest odzwierciedlone we wzroście przewodnictwa skóry, a obniżenie poziomu pobudzenia kory mózgowej jest związane z obniżeniem przewodnictwa skóry.&lt;br /&gt;
&lt;br /&gt;
Za pomocą czułej metody mierzącej i przekazującej poziom pobudzenia, może on być świadomie kontrolowany w szerokim zakresie. Metoda ta jest wykorzystywana w psychologii, medycynie, sporcie i biznesie.&lt;br /&gt;
==Dodatkowa lektura==&lt;br /&gt;
 Polecamy zapoznanie się z rozdziałem 27 książki dostępnej pod adresem [http://www.bem.fi/book/].&lt;br /&gt;
&lt;br /&gt;
==Ćwiczenia==&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Ćwiczenie I (Pomiar składowej stałej i habituacja)===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wykonaj pomiar GSR dwoma metodami.&lt;br /&gt;
* Parą elektrod bipolarnych do EMG umieszczonych na zewnętrznej i wewnętrznej stronie dłoni. Elektrodę referencyjną umieść np. na brzuchu.&lt;br /&gt;
* Parą elektrod do GSR. Użyj kabla do pomiaru GSR z pięcioma stykami. Na elektrody do GSR nałóż żel w punkcie metalowego kontaktu. Załóż elektrody na palec wskazujący i środkowy. Kontakty powinny znajdować się po wewnętrznej stronie dłoni, gdyż jest tam większa ilość kanałów potowych. &lt;br /&gt;
* Skonfiguruj program do rejestracji i przeglądania mierzonego sygnału w czasie rzeczywistym.&lt;br /&gt;
* Opisz rejestrowane sygnały.&lt;br /&gt;
* Wykonaj eksperyment. Gdy osoba badana siedzi spokojnie i bez poruszania się, druga osoba zadaje mu pytanie:&lt;br /&gt;
**  &amp;quot;Czy masz na imię X&amp;quot;, gdzie X oznacza prawdziwe imię.&lt;br /&gt;
**  Badany odpowiada &amp;quot;Tak&amp;quot;, po każdym pytaniu. &lt;br /&gt;
** Po powrocie sygnału do poziomu odniesienia, druga osoba ponownie zadaje mu pytanie. &lt;br /&gt;
** Proces zadawania pytań trwa tak długo, dopóki badany nie wykaże reakcji w sygnale, przez trzy kolejne pytania. Brak reakcji w sygnale nazywa się habituacją.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
===Ćwiczenie I: &amp;quot;Wykrywacz kłamstwa&amp;quot;?===&lt;br /&gt;
ONLINE:&lt;br /&gt;
&lt;br /&gt;
Użyj kabla do pomiaru GSR z pięcioma stykami.  Załóż elektrody na palec wskazujący i środkowy. Kontakty powinny znajdować się po wewnętrznej stronie dłoni, gdyż jest tam większa ilość kanałów potowych. &lt;br /&gt;
* Użyj programu w psychopy z listą ~30 pytań i tagami do oznacznia momentu wyświetlenia pytania, momentu i typu odpowiedzi, i uruchamiania następnego pytania. Klawiaturę obsługuje eksperymentator, osoba badana obserwuje ekran i opowiada na pytania na głos  Tak lub Nie.&lt;br /&gt;
* Po zadaniu pytania obserwuj reakcje skórno-galwaniczną. Poczekaj aż przewodnictwo wróci do poziomu odniesienia, zanim wciśniesz przycisk uruchamiający następne pytanie. Eksperymentator odczytuje pytanie. &lt;br /&gt;
* Skonfiguruj program do rejestracji i przeglądania mierzonego sygnału w czasie rzeczywistym.&lt;br /&gt;
* Przekaż osobie badanej, siedziała spokojnie i odpowiadała na zadawane pytanie &amp;amp;bdquo;Tak&amp;amp;rdquo; lub &amp;amp;bdquo;Nie&amp;amp;rdquo;.Osoba badana powinna samodzielnie wybrać czy odpowie zgodnie z prawdą. Należy postarać się aby odpowiedzi prawdziwych i fałszywych było tyle samo. &lt;br /&gt;
* Gdy zadasz wszystkie pytania i zapiszesz ostatnią reakcję zatrzymaj rejestrację.&lt;br /&gt;
&lt;br /&gt;
OFFLINE: &lt;br /&gt;
* Wczytać sygnał i tagi do pythona. Osoba badana powina dla każdej odpowiedzi dodać informację czy odpowiadała zgodnie z prawdą.&lt;br /&gt;
* podziel sygnały na grupę Prawda i Fałsz wycinając 12s od zadania pytania/względem udzielenia odpowiedzi (-5 +7s względem tego momentu).&lt;br /&gt;
* Dla każdej odpowiedzi GSR oszacuj latencję, amplitudę, czas narastania i czas połowicznego zaniku. Zbadaj rozrzut wyników. Jeśli odpowiedzi są podobne, uśrednij wyniki i wyznacz średnią latencję, amplitudę, czas narastania i czas połowicznego zaniku. Czy są jakieś różnice pomiędzy grupą Prawda i Fałsz?&lt;br /&gt;
&lt;br /&gt;
Lista pytań:&lt;br /&gt;
# Czy mieszkasz w Warszawie?&lt;br /&gt;
# Czy lubisz brokuły?&lt;br /&gt;
# Czy masz kota?&lt;br /&gt;
# Czy urodziłeś/aś się w Polsce?&lt;br /&gt;
# Czy jeździsz na łyżwach?&lt;br /&gt;
# Czy masz brata?&lt;br /&gt;
# Czy byłeś/aś w Hiszpanii?&lt;br /&gt;
# Czy studiujesz na UW?&lt;br /&gt;
# Czy dzisiaj jest wtorek?&lt;br /&gt;
# Czy lubisz pizzę?&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie III (Analiza składowej zmiennej dla obrazów z zawartością neutralną i emocjonalną)===&lt;br /&gt;
W tym samym układzie doświadczalnym jak w Ćwiczeniu I i II wykonaj następujący eksperyment.&lt;br /&gt;
* Przekaż osobie badanej, by siedziała spokojnie.&lt;br /&gt;
* Rozpocznij rejestrację sygnału&lt;br /&gt;
* Uruchom program ..... wyświetlający losowo obrazy o zawartości neutralnej i emocjonalnej. Wyświetlaj obrazki naciskając klawisz klawiatury. Po wyświetleniu obrazka obserwuj reakcje skórno-galwaniczną. Poczekaj aż przewodnictwo wróci do poziomu odniesienia, zanim wyświetlisz następny obrazek.&lt;br /&gt;
* Gdy pojawi się napis &amp;amp;bdquo;Koniec&amp;amp;rdquo;, odczekaj 10 sekund i zatrzymaj rejestrację.&lt;br /&gt;
* Odczytaj momenty wyświetlania obrazów neutralnych i emocjonalnych zapisane przez program. Na podstawie tych danych, dla każdej odpowiedzi na obraz emocjonalny oszacuj latencję, amplitudę, czas narastania bez czasu połowicznego zaniku. Zbadaj rozrzut wyników. Jeśli odpowiedzi są podobne, uśrednij wyniki i wyznacz średnią latencję, amplitudę, czas narastania.&lt;br /&gt;
*Porównaj uśrednione parametry odpowiedzi GSR dla obrazów emocjonalnych i słów neutralnych otrzymanych w Ćwiczeniu II.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:EOG.pdf&amp;diff=8024</id>
		<title>Plik:EOG.pdf</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:EOG.pdf&amp;diff=8024"/>
		<updated>2019-05-06T11:49:20Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: Gbernatowicz przesłał nową wersję Plik:EOG.pdf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:EOG.pdf&amp;diff=8023</id>
		<title>Plik:EOG.pdf</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:EOG.pdf&amp;diff=8023"/>
		<updated>2019-05-06T11:30:11Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8022</id>
		<title>Pracownia Sygnałów Biologicznych/Zajecia 7</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8022"/>
		<updated>2019-05-06T11:29:52Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Wstęp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;b&amp;gt;Pomiar Elektrookulogramu&amp;lt;/b&amp;gt;&lt;br /&gt;
==Wstęp==&lt;br /&gt;
&lt;br /&gt;
Prezentacja: [[Media:EOG.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejnym narządem, w którym znajdują się generatory czynności bioelektrycznej jest oko. W narządzie tym zachodzą skomplikowane procesy biochemiczne i elektryczne, umożliwiające widzenie. Procesy te zostaną omówione na oddzielnym wykładzie, w tym miejscu zaś wymienimy tylko te zjawiska, które mają wpływ na powstawanie w oku czynności elektrycznej.&lt;br /&gt;
# Jednym z najważniejszych części oka jest ''siatkówka'', której zadaniem jest odbieranie bodźców świetlnych oraz zamiana ich na sygnały elektryczne, przekazywane dalej do kory wzrokowej. W siatkówce płynie nieustannie prąd, którego natężenie zmienia się wraz z intensywnością padającego na nią światła. Związane z tym sygnały bioelektryczne można rejestrować za pomocą elektrod umieszczonych na powierzchni oka lub nawet za pomocą elektrod umieszczonych na powierzchni skóry wokół oka. Tak zarejestrowany sygnał elektryczny, powstały w oku w trakcie widzenia, nazywamy ''Elektroretinogramem'' (ERG). Sygnał ten ma amplitudę od kilku nanowoltów do kilku &amp;amp;mu;V i jest wykorzystywany w diagnostyce wielu chorób siatkówki. &lt;br /&gt;
# Rogówka (zewnętrzna warstwa oka znajdująca się w jego przedniej części) jest naładowana dodatnio względem siatkówki umiejscowionej po przeciwnej stronie oka. Rogówka wraz z siatkówką tworzą zatem w przybliżeniu układ dipola elektrycznego. W momencie ruchu okiem, dipol ten zmienia orientację w przestrzeni, zaburzając rozkład natężenia pola elektrycznego. Związany z tym sygnał o amplitudzie kilku miliwoltów można zmierzyć za pomocą elektrod umieszczonych na skórze wokół oka. Widoczny jest ona także na elektrodach umieszczonych na powierzchni głowy w trakcie pomiary czynności elektrycznej mózgu. Sygnał ten, czyli elektryczny zapis ruchu gałek ocznych, nazywamy Elektrookulogramem (EOG). Czynność elektryczną związaną z ruchem gałek ocznych obserwuje się również w trakcie mrugania, kiedy to gałki oczne skręcają nieco ku górze (tzw. zjawiska Bella), a także w trakcie badań diagnostycznych zaburzeń snu (w różnych etapach snu występują wolne lub szybkie ruchy gałek ocznych).&lt;br /&gt;
Sygnał EOG można też wykorzystać do konstrukcji interfejsów [[http://dl.acm.org/citation.cfm?id=1740647]].&lt;br /&gt;
# Ruch oka sterowany jest za pomocą mięśni. W trakcie rejestracji Elektrookulogramu widoczne będą również wyładowania elektryczne związane z działaniem mięśni.&lt;br /&gt;
===Ćwiczenie I: Podstawowe własności sygnału EOG ===&lt;br /&gt;
Wykonaj pomiar Elektrokulogramu za pomocą dwóch par elektrod połączonych w montażu dwubiegunowym. &lt;br /&gt;
&amp;lt;!--* Umieść jedną z elektrod nieco przyśrodkowo i nieznacznie powyżej szpary powiekowej, drugą zaś a po przeciwległej stronie, tj. nieco poniżej szpary powiekowej. --&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przyjrzyj się na bieżąco w SVAROGu sygnałom w poniższych sytuacjach, a następnie zarejestruj odpowiadajće im sygnały aby dało się je przedstawić w prezentacji.&lt;br /&gt;
&lt;br /&gt;
* Jedną parę elektrod umieść poniżej i powyżej oka, drugą w pobliżu lewej i prawej skroni.&lt;br /&gt;
* Skonfiguruj program do rejestracji i przeglądania mierzonego sygnału w czasie rzeczywistym.&lt;br /&gt;
* Wykonaj ruch oczami w górę i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj ruch oczami w dół i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj mrugnięcie i opisz zarejestrowany sygnał.&lt;br /&gt;
* Przeczytaj fragment tekstu, zaobserwuj efekty związane z ruchem sakadowym oka.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, rozważ efekty stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Ćwiczenie II ===&lt;br /&gt;
Powtórz ćwiczenie I, łącząc elektrody z monopolarnymi wejściami wzmacniacza, elektrodę odniesienia umieść na lewym płatku uszu lub wyrostku sutkowatym.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie II: dekoder sakad ===&lt;br /&gt;
Napisz program wyświetlający na macierzy 5x5 następujące sekwencje:&lt;br /&gt;
* kwadrat środkowy - kwadrat górny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat prawy - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat dolny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat lewy - kwadrat środkowy&lt;br /&gt;
Zapisuj do pliku tekstowego czasy i kody poszczególnych sekwencji. Powtórz po kilkanaście sekwencji całości.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, bez stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
Zaprojektuj detektor, wykrywający, która sekwencja została wykonana. Przetestuj go na zebrnym sygnale off-line.&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie III: interfejs 'sakadowy' ===&lt;br /&gt;
Zrealizuj prosty system do analizy on-line ruchu gałki ocznej, modyfikując detektor z poprzedniego ćwiczenia. W najprostszej wersji system ma wypisywać w terminalu wykryty kierunek sakady.&lt;br /&gt;
 (http://laboratorium-eeg.braintech.pl/rozdz11.html)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
w tym celu:&lt;br /&gt;
==== Napisz moduł:====&lt;br /&gt;
* Korzystając detektora sekwencji napisanego w ramach ćwiczenia III napisz moduł wykrywający sekwencje w czasie rzeczywistym.  Niech Twój moduł wypisuje wynik detekcji na konsolę.  '''Opis korzystania i pisania modułów do  systemu OBCI znajduje się''' [[http://bci.fuw.edu.pl/wiki/Tutorials tutaj]]. W dużym skrócie to co należy zrobić to:&lt;br /&gt;
 &lt;br /&gt;
* W  katalogu domowym utwórz podkatalog: &lt;br /&gt;
 ~/obci/scenarios&lt;br /&gt;
* w katalogu tym umieść plik:&lt;br /&gt;
 eog.ini&lt;br /&gt;
powinien on zawierać następującą treść:&lt;br /&gt;
&amp;lt;source lang = 'text'&amp;gt;&lt;br /&gt;
[peers]&lt;br /&gt;
scenario_dir=&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.mx]&lt;br /&gt;
path=multiplexer-install/bin/mxcontrol&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.config_server]&lt;br /&gt;
path=control/peer/config_server.py&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.amplifier]&lt;br /&gt;
path = drivers/eeg/cpp_amplifiers/amplifier_tmsi.py&lt;br /&gt;
;ponizsza sciezka pokazuje na plik zaierajacy nasze ustawienia parametrow wzmacniacza&lt;br /&gt;
config=~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
&lt;br /&gt;
[peers.analysis]&lt;br /&gt;
path=~/obci/analysis/eog_realtime.py&lt;br /&gt;
config=~/obci/analysis/eog_realtime.ini&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* W powyższym pliku zadeklarowaliśmy, że lokalne parametry dla wzmacniacza znajduję się w pliku:&lt;br /&gt;
 ~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
zatem musimy ten plik wytworzyć i wypełnić go np. taką treścią:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
[local_params]&lt;br /&gt;
channel_names=gora;dol;lewa;prawa&lt;br /&gt;
active_channels=0;1;2;3&lt;br /&gt;
sampling_rate=256&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
* W pliku ze scenariuszem zadeklarowaliśmy też, że nasz moduł analizy danych znajduje się w pliku:&lt;br /&gt;
 ~/obci/analysis/eog_realtime.py&lt;br /&gt;
tak więc musimy ten plik stworzyć i tam właśnie wpisać algorytm detekcji. Dla zachowania konwencji w tym samym katalogu powinien znajdować się plik na ewentualne parametry dla modułu eog_realtime.py. Musi on się nazywać tak samo, tyle, że ma rozszerzenie .ini. Musimy więc wytworzyć pusty plik:  &lt;br /&gt;
 ~/obci/analysis/eog_realtime.ini&lt;br /&gt;
Ponieważ nasz algorytm musi on się komunikować z resztą systemu obci trzeba go opakować w poniższy kod-szkielet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import random, time, numpy&lt;br /&gt;
 &lt;br /&gt;
from multiplexer.multiplexer_constants import peers, types&lt;br /&gt;
from obci.control.peer.configured_multiplexer_server import ConfiguredMultiplexerServer&lt;br /&gt;
from obci.configs import settings, variables_pb2&lt;br /&gt;
from collections import deque&lt;br /&gt;
 &lt;br /&gt;
import obci.utils.openbci_logging as logger&lt;br /&gt;
&lt;br /&gt;
#LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;info&amp;quot;)&lt;br /&gt;
LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;debug&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
class SampleAnalysis(ConfiguredMultiplexerServer):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;A class responsible for handling signal message and making proper decision.&lt;br /&gt;
    The class inherits from generic class for convinience - all technical stuff&lt;br /&gt;
    is being done in this super-class&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self, addresses):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Initialization - super() and ready() calls are required...&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        super(SampleAnalysis, self).__init__(addresses=addresses,&lt;br /&gt;
                                          type=peers.ANALYSIS)&lt;br /&gt;
        self.ready()&lt;br /&gt;
        LOGGER.info(&amp;quot;Sample analysis init finished!&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def handle_message(self, mxmsg):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;The only required function in the class&lt;br /&gt;
        that will be fired every time message is received&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if mxmsg.type == types.AMPLIFIER_SIGNAL_MESSAGE:&lt;br /&gt;
            # Got proper message, let`s unpack it ...&lt;br /&gt;
 &lt;br /&gt;
            # Messages are transmitted in bunches so lets define SampleVector&lt;br /&gt;
            # in order to unpack bunch of Sample messages ...&lt;br /&gt;
	    l_vect = variables_pb2.SampleVector()&lt;br /&gt;
            l_vect.ParseFromString(mxmsg.message)&lt;br /&gt;
 &lt;br /&gt;
            # Now we have message unpacked, lets iterate over every sample ...&lt;br /&gt;
            for s in l_vect.samples:&lt;br /&gt;
 &lt;br /&gt;
                # Every sample has two fields:&lt;br /&gt;
                # timestamp - system clock time of a moment of Sample`s creation&lt;br /&gt;
                # channels - a list of values - one for every channel&lt;br /&gt;
                LOGGER.debug(&amp;quot;Got sample with timestamp: &amp;quot;+str(s.timestamp))&lt;br /&gt;
 &lt;br /&gt;
                # One can copy samples to numpy array ...&lt;br /&gt;
&lt;br /&gt;
                a = numpy.array(s.channels) # w tym miejscu mamy w tablicy a &amp;quot;paczke&amp;quot; próbek (domyślnie 4próbki ) ze wszystkich zadeklarowanych kanalow &lt;br /&gt;
#################### TU TRZEBA WPISAC SWOJ KOD BUFOROWANIA i ANALIZY  ##############&lt;br /&gt;
                print a #na dobry poczatek wypiszmy probki&lt;br /&gt;
&lt;br /&gt;
####################################################################&lt;br /&gt;
 &lt;br /&gt;
                # Or just iterate over values ...&lt;br /&gt;
                for ch in s.channels:&lt;br /&gt;
                    LOGGER.debug(ch)&lt;br /&gt;
 &lt;br /&gt;
            # Having a new bunch of values one can fire some magic analysis and &lt;br /&gt;
            # generate decision ....&lt;br /&gt;
 &lt;br /&gt;
            # Below we have quite simple decision-maker - it generates a random&lt;br /&gt;
            # decision every ~100 samples-bunch&lt;br /&gt;
########## TU NA PODSTAWIE ANALLIZY PODEJMUJEMY DECYZJE I MOZEMY JA PRZEKAZAC DO RESZTY SYSTEMU OBCI ######################&lt;br /&gt;
########## W TYM PRZYKLADZIE JEST TO LOSOWA DECYZJA ##############&lt;br /&gt;
########## W TYM CWICZENIU WYSTARCZY JESLI WYPISZECIE DECYZJE NA EKRAN ###########&lt;br /&gt;
            if random.random() &amp;gt; 0.99:&lt;br /&gt;
                # Here we send DECISION message somewhere-to-the-system ...&lt;br /&gt;
                # It's up to scenario's configuration how the decision will be used ...&lt;br /&gt;
                # Eg. it might be used by LOGIC module to push some button in speller.&lt;br /&gt;
                self.conn.send_message(message = str(random.randint(0,7)), &lt;br /&gt;
                                       type = types.DECISION_MESSAGE, &lt;br /&gt;
                                       flush=True)&lt;br /&gt;
        else:&lt;br /&gt;
            LOGGER.warning(&amp;quot;Got unrecognised message type: &amp;quot;+str(mxmsg.type))&lt;br /&gt;
 &lt;br /&gt;
        # Tell the system 'I`ll not respond to this message, I`m just receiving'&lt;br /&gt;
        self.no_response()&lt;br /&gt;
 &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    # Initialize and run an object in order to have your analysis up and running&lt;br /&gt;
    SampleAnalysis(settings.MULTIPLEXER_ADDRESSES).loop()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Aby uruchomić nasz scenariusz trzeba wywołać:&lt;br /&gt;
 obci launch ~/obci/scenarios/eog.ini&lt;br /&gt;
* Zatrzymanie scenariusza robimy tak:&lt;br /&gt;
 obci kill eog&lt;br /&gt;
W tym momencie komunikaty ze wszystkich modułów wypisywane są na jednej konsoli. Przydatne jest korzystanie z obiektu 'LOGGER' zamiast funkcji 'print' - w konsoli mamy informację o źródle komunikatu i jego czasie.&lt;br /&gt;
&lt;br /&gt;
OpenBCI działa tak, że jeśli w jednym module pojawi się błąd, to wszystkie inne moduły są zamykane, stąd komunikat podobny do poniższego sugeruje, że w którymś module wystąpił błąd. W takim wypadku należy przejrzeć konsolę i wyszukać komunikat błędu. Niezbędne jest ustawienie bufora konsoli na 'nieograniczony' wykonując: Edycja-&amp;gt;Preferencje profilu-&amp;gt;Przewijanie-&amp;gt;Nieograniczone .&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
====Przetestuj moduł ====&lt;br /&gt;
* Umieść elektrody do rejestracji ruchu gałki ocznej jak w ćwiczeniu I i przetestuj działanie modułu. Miłej zabawy :-)&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8021</id>
		<title>Pracownia Sygnałów Biologicznych/Zajecia 7</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8021"/>
		<updated>2019-05-06T11:29:00Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Wstęp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;b&amp;gt;Pomiar Elektrookulogramu&amp;lt;/b&amp;gt;&lt;br /&gt;
==Wstęp==&lt;br /&gt;
&lt;br /&gt;
Prezentacja: [[EOG.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejnym narządem, w którym znajdują się generatory czynności bioelektrycznej jest oko. W narządzie tym zachodzą skomplikowane procesy biochemiczne i elektryczne, umożliwiające widzenie. Procesy te zostaną omówione na oddzielnym wykładzie, w tym miejscu zaś wymienimy tylko te zjawiska, które mają wpływ na powstawanie w oku czynności elektrycznej.&lt;br /&gt;
# Jednym z najważniejszych części oka jest ''siatkówka'', której zadaniem jest odbieranie bodźców świetlnych oraz zamiana ich na sygnały elektryczne, przekazywane dalej do kory wzrokowej. W siatkówce płynie nieustannie prąd, którego natężenie zmienia się wraz z intensywnością padającego na nią światła. Związane z tym sygnały bioelektryczne można rejestrować za pomocą elektrod umieszczonych na powierzchni oka lub nawet za pomocą elektrod umieszczonych na powierzchni skóry wokół oka. Tak zarejestrowany sygnał elektryczny, powstały w oku w trakcie widzenia, nazywamy ''Elektroretinogramem'' (ERG). Sygnał ten ma amplitudę od kilku nanowoltów do kilku &amp;amp;mu;V i jest wykorzystywany w diagnostyce wielu chorób siatkówki. &lt;br /&gt;
# Rogówka (zewnętrzna warstwa oka znajdująca się w jego przedniej części) jest naładowana dodatnio względem siatkówki umiejscowionej po przeciwnej stronie oka. Rogówka wraz z siatkówką tworzą zatem w przybliżeniu układ dipola elektrycznego. W momencie ruchu okiem, dipol ten zmienia orientację w przestrzeni, zaburzając rozkład natężenia pola elektrycznego. Związany z tym sygnał o amplitudzie kilku miliwoltów można zmierzyć za pomocą elektrod umieszczonych na skórze wokół oka. Widoczny jest ona także na elektrodach umieszczonych na powierzchni głowy w trakcie pomiary czynności elektrycznej mózgu. Sygnał ten, czyli elektryczny zapis ruchu gałek ocznych, nazywamy Elektrookulogramem (EOG). Czynność elektryczną związaną z ruchem gałek ocznych obserwuje się również w trakcie mrugania, kiedy to gałki oczne skręcają nieco ku górze (tzw. zjawiska Bella), a także w trakcie badań diagnostycznych zaburzeń snu (w różnych etapach snu występują wolne lub szybkie ruchy gałek ocznych).&lt;br /&gt;
Sygnał EOG można też wykorzystać do konstrukcji interfejsów [[http://dl.acm.org/citation.cfm?id=1740647]].&lt;br /&gt;
# Ruch oka sterowany jest za pomocą mięśni. W trakcie rejestracji Elektrookulogramu widoczne będą również wyładowania elektryczne związane z działaniem mięśni.&lt;br /&gt;
===Ćwiczenie I: Podstawowe własności sygnału EOG ===&lt;br /&gt;
Wykonaj pomiar Elektrokulogramu za pomocą dwóch par elektrod połączonych w montażu dwubiegunowym. &lt;br /&gt;
&amp;lt;!--* Umieść jedną z elektrod nieco przyśrodkowo i nieznacznie powyżej szpary powiekowej, drugą zaś a po przeciwległej stronie, tj. nieco poniżej szpary powiekowej. --&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przyjrzyj się na bieżąco w SVAROGu sygnałom w poniższych sytuacjach, a następnie zarejestruj odpowiadajće im sygnały aby dało się je przedstawić w prezentacji.&lt;br /&gt;
&lt;br /&gt;
* Jedną parę elektrod umieść poniżej i powyżej oka, drugą w pobliżu lewej i prawej skroni.&lt;br /&gt;
* Skonfiguruj program do rejestracji i przeglądania mierzonego sygnału w czasie rzeczywistym.&lt;br /&gt;
* Wykonaj ruch oczami w górę i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj ruch oczami w dół i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj mrugnięcie i opisz zarejestrowany sygnał.&lt;br /&gt;
* Przeczytaj fragment tekstu, zaobserwuj efekty związane z ruchem sakadowym oka.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, rozważ efekty stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Ćwiczenie II ===&lt;br /&gt;
Powtórz ćwiczenie I, łącząc elektrody z monopolarnymi wejściami wzmacniacza, elektrodę odniesienia umieść na lewym płatku uszu lub wyrostku sutkowatym.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie II: dekoder sakad ===&lt;br /&gt;
Napisz program wyświetlający na macierzy 5x5 następujące sekwencje:&lt;br /&gt;
* kwadrat środkowy - kwadrat górny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat prawy - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat dolny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat lewy - kwadrat środkowy&lt;br /&gt;
Zapisuj do pliku tekstowego czasy i kody poszczególnych sekwencji. Powtórz po kilkanaście sekwencji całości.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, bez stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
Zaprojektuj detektor, wykrywający, która sekwencja została wykonana. Przetestuj go na zebrnym sygnale off-line.&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie III: interfejs 'sakadowy' ===&lt;br /&gt;
Zrealizuj prosty system do analizy on-line ruchu gałki ocznej, modyfikując detektor z poprzedniego ćwiczenia. W najprostszej wersji system ma wypisywać w terminalu wykryty kierunek sakady.&lt;br /&gt;
 (http://laboratorium-eeg.braintech.pl/rozdz11.html)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
w tym celu:&lt;br /&gt;
==== Napisz moduł:====&lt;br /&gt;
* Korzystając detektora sekwencji napisanego w ramach ćwiczenia III napisz moduł wykrywający sekwencje w czasie rzeczywistym.  Niech Twój moduł wypisuje wynik detekcji na konsolę.  '''Opis korzystania i pisania modułów do  systemu OBCI znajduje się''' [[http://bci.fuw.edu.pl/wiki/Tutorials tutaj]]. W dużym skrócie to co należy zrobić to:&lt;br /&gt;
 &lt;br /&gt;
* W  katalogu domowym utwórz podkatalog: &lt;br /&gt;
 ~/obci/scenarios&lt;br /&gt;
* w katalogu tym umieść plik:&lt;br /&gt;
 eog.ini&lt;br /&gt;
powinien on zawierać następującą treść:&lt;br /&gt;
&amp;lt;source lang = 'text'&amp;gt;&lt;br /&gt;
[peers]&lt;br /&gt;
scenario_dir=&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.mx]&lt;br /&gt;
path=multiplexer-install/bin/mxcontrol&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.config_server]&lt;br /&gt;
path=control/peer/config_server.py&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.amplifier]&lt;br /&gt;
path = drivers/eeg/cpp_amplifiers/amplifier_tmsi.py&lt;br /&gt;
;ponizsza sciezka pokazuje na plik zaierajacy nasze ustawienia parametrow wzmacniacza&lt;br /&gt;
config=~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
&lt;br /&gt;
[peers.analysis]&lt;br /&gt;
path=~/obci/analysis/eog_realtime.py&lt;br /&gt;
config=~/obci/analysis/eog_realtime.ini&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* W powyższym pliku zadeklarowaliśmy, że lokalne parametry dla wzmacniacza znajduję się w pliku:&lt;br /&gt;
 ~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
zatem musimy ten plik wytworzyć i wypełnić go np. taką treścią:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
[local_params]&lt;br /&gt;
channel_names=gora;dol;lewa;prawa&lt;br /&gt;
active_channels=0;1;2;3&lt;br /&gt;
sampling_rate=256&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
* W pliku ze scenariuszem zadeklarowaliśmy też, że nasz moduł analizy danych znajduje się w pliku:&lt;br /&gt;
 ~/obci/analysis/eog_realtime.py&lt;br /&gt;
tak więc musimy ten plik stworzyć i tam właśnie wpisać algorytm detekcji. Dla zachowania konwencji w tym samym katalogu powinien znajdować się plik na ewentualne parametry dla modułu eog_realtime.py. Musi on się nazywać tak samo, tyle, że ma rozszerzenie .ini. Musimy więc wytworzyć pusty plik:  &lt;br /&gt;
 ~/obci/analysis/eog_realtime.ini&lt;br /&gt;
Ponieważ nasz algorytm musi on się komunikować z resztą systemu obci trzeba go opakować w poniższy kod-szkielet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import random, time, numpy&lt;br /&gt;
 &lt;br /&gt;
from multiplexer.multiplexer_constants import peers, types&lt;br /&gt;
from obci.control.peer.configured_multiplexer_server import ConfiguredMultiplexerServer&lt;br /&gt;
from obci.configs import settings, variables_pb2&lt;br /&gt;
from collections import deque&lt;br /&gt;
 &lt;br /&gt;
import obci.utils.openbci_logging as logger&lt;br /&gt;
&lt;br /&gt;
#LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;info&amp;quot;)&lt;br /&gt;
LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;debug&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
class SampleAnalysis(ConfiguredMultiplexerServer):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;A class responsible for handling signal message and making proper decision.&lt;br /&gt;
    The class inherits from generic class for convinience - all technical stuff&lt;br /&gt;
    is being done in this super-class&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self, addresses):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Initialization - super() and ready() calls are required...&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        super(SampleAnalysis, self).__init__(addresses=addresses,&lt;br /&gt;
                                          type=peers.ANALYSIS)&lt;br /&gt;
        self.ready()&lt;br /&gt;
        LOGGER.info(&amp;quot;Sample analysis init finished!&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def handle_message(self, mxmsg):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;The only required function in the class&lt;br /&gt;
        that will be fired every time message is received&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if mxmsg.type == types.AMPLIFIER_SIGNAL_MESSAGE:&lt;br /&gt;
            # Got proper message, let`s unpack it ...&lt;br /&gt;
 &lt;br /&gt;
            # Messages are transmitted in bunches so lets define SampleVector&lt;br /&gt;
            # in order to unpack bunch of Sample messages ...&lt;br /&gt;
	    l_vect = variables_pb2.SampleVector()&lt;br /&gt;
            l_vect.ParseFromString(mxmsg.message)&lt;br /&gt;
 &lt;br /&gt;
            # Now we have message unpacked, lets iterate over every sample ...&lt;br /&gt;
            for s in l_vect.samples:&lt;br /&gt;
 &lt;br /&gt;
                # Every sample has two fields:&lt;br /&gt;
                # timestamp - system clock time of a moment of Sample`s creation&lt;br /&gt;
                # channels - a list of values - one for every channel&lt;br /&gt;
                LOGGER.debug(&amp;quot;Got sample with timestamp: &amp;quot;+str(s.timestamp))&lt;br /&gt;
 &lt;br /&gt;
                # One can copy samples to numpy array ...&lt;br /&gt;
&lt;br /&gt;
                a = numpy.array(s.channels) # w tym miejscu mamy w tablicy a &amp;quot;paczke&amp;quot; próbek (domyślnie 4próbki ) ze wszystkich zadeklarowanych kanalow &lt;br /&gt;
#################### TU TRZEBA WPISAC SWOJ KOD BUFOROWANIA i ANALIZY  ##############&lt;br /&gt;
                print a #na dobry poczatek wypiszmy probki&lt;br /&gt;
&lt;br /&gt;
####################################################################&lt;br /&gt;
 &lt;br /&gt;
                # Or just iterate over values ...&lt;br /&gt;
                for ch in s.channels:&lt;br /&gt;
                    LOGGER.debug(ch)&lt;br /&gt;
 &lt;br /&gt;
            # Having a new bunch of values one can fire some magic analysis and &lt;br /&gt;
            # generate decision ....&lt;br /&gt;
 &lt;br /&gt;
            # Below we have quite simple decision-maker - it generates a random&lt;br /&gt;
            # decision every ~100 samples-bunch&lt;br /&gt;
########## TU NA PODSTAWIE ANALLIZY PODEJMUJEMY DECYZJE I MOZEMY JA PRZEKAZAC DO RESZTY SYSTEMU OBCI ######################&lt;br /&gt;
########## W TYM PRZYKLADZIE JEST TO LOSOWA DECYZJA ##############&lt;br /&gt;
########## W TYM CWICZENIU WYSTARCZY JESLI WYPISZECIE DECYZJE NA EKRAN ###########&lt;br /&gt;
            if random.random() &amp;gt; 0.99:&lt;br /&gt;
                # Here we send DECISION message somewhere-to-the-system ...&lt;br /&gt;
                # It's up to scenario's configuration how the decision will be used ...&lt;br /&gt;
                # Eg. it might be used by LOGIC module to push some button in speller.&lt;br /&gt;
                self.conn.send_message(message = str(random.randint(0,7)), &lt;br /&gt;
                                       type = types.DECISION_MESSAGE, &lt;br /&gt;
                                       flush=True)&lt;br /&gt;
        else:&lt;br /&gt;
            LOGGER.warning(&amp;quot;Got unrecognised message type: &amp;quot;+str(mxmsg.type))&lt;br /&gt;
 &lt;br /&gt;
        # Tell the system 'I`ll not respond to this message, I`m just receiving'&lt;br /&gt;
        self.no_response()&lt;br /&gt;
 &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    # Initialize and run an object in order to have your analysis up and running&lt;br /&gt;
    SampleAnalysis(settings.MULTIPLEXER_ADDRESSES).loop()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Aby uruchomić nasz scenariusz trzeba wywołać:&lt;br /&gt;
 obci launch ~/obci/scenarios/eog.ini&lt;br /&gt;
* Zatrzymanie scenariusza robimy tak:&lt;br /&gt;
 obci kill eog&lt;br /&gt;
W tym momencie komunikaty ze wszystkich modułów wypisywane są na jednej konsoli. Przydatne jest korzystanie z obiektu 'LOGGER' zamiast funkcji 'print' - w konsoli mamy informację o źródle komunikatu i jego czasie.&lt;br /&gt;
&lt;br /&gt;
OpenBCI działa tak, że jeśli w jednym module pojawi się błąd, to wszystkie inne moduły są zamykane, stąd komunikat podobny do poniższego sugeruje, że w którymś module wystąpił błąd. W takim wypadku należy przejrzeć konsolę i wyszukać komunikat błędu. Niezbędne jest ustawienie bufora konsoli na 'nieograniczony' wykonując: Edycja-&amp;gt;Preferencje profilu-&amp;gt;Przewijanie-&amp;gt;Nieograniczone .&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
====Przetestuj moduł ====&lt;br /&gt;
* Umieść elektrody do rejestracji ruchu gałki ocznej jak w ćwiczeniu I i przetestuj działanie modułu. Miłej zabawy :-)&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8020</id>
		<title>Pracownia Sygnałów Biologicznych/Zajecia 7</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_Sygna%C5%82%C3%B3w_Biologicznych/Zajecia_7&amp;diff=8020"/>
		<updated>2019-05-06T11:27:33Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Wstęp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;b&amp;gt;Pomiar Elektrookulogramu&amp;lt;/b&amp;gt;&lt;br /&gt;
==Wstęp==&lt;br /&gt;
&lt;br /&gt;
Prezentacja: &lt;br /&gt;
&lt;br /&gt;
Kolejnym narządem, w którym znajdują się generatory czynności bioelektrycznej jest oko. W narządzie tym zachodzą skomplikowane procesy biochemiczne i elektryczne, umożliwiające widzenie. Procesy te zostaną omówione na oddzielnym wykładzie, w tym miejscu zaś wymienimy tylko te zjawiska, które mają wpływ na powstawanie w oku czynności elektrycznej.&lt;br /&gt;
# Jednym z najważniejszych części oka jest ''siatkówka'', której zadaniem jest odbieranie bodźców świetlnych oraz zamiana ich na sygnały elektryczne, przekazywane dalej do kory wzrokowej. W siatkówce płynie nieustannie prąd, którego natężenie zmienia się wraz z intensywnością padającego na nią światła. Związane z tym sygnały bioelektryczne można rejestrować za pomocą elektrod umieszczonych na powierzchni oka lub nawet za pomocą elektrod umieszczonych na powierzchni skóry wokół oka. Tak zarejestrowany sygnał elektryczny, powstały w oku w trakcie widzenia, nazywamy ''Elektroretinogramem'' (ERG). Sygnał ten ma amplitudę od kilku nanowoltów do kilku &amp;amp;mu;V i jest wykorzystywany w diagnostyce wielu chorób siatkówki. &lt;br /&gt;
# Rogówka (zewnętrzna warstwa oka znajdująca się w jego przedniej części) jest naładowana dodatnio względem siatkówki umiejscowionej po przeciwnej stronie oka. Rogówka wraz z siatkówką tworzą zatem w przybliżeniu układ dipola elektrycznego. W momencie ruchu okiem, dipol ten zmienia orientację w przestrzeni, zaburzając rozkład natężenia pola elektrycznego. Związany z tym sygnał o amplitudzie kilku miliwoltów można zmierzyć za pomocą elektrod umieszczonych na skórze wokół oka. Widoczny jest ona także na elektrodach umieszczonych na powierzchni głowy w trakcie pomiary czynności elektrycznej mózgu. Sygnał ten, czyli elektryczny zapis ruchu gałek ocznych, nazywamy Elektrookulogramem (EOG). Czynność elektryczną związaną z ruchem gałek ocznych obserwuje się również w trakcie mrugania, kiedy to gałki oczne skręcają nieco ku górze (tzw. zjawiska Bella), a także w trakcie badań diagnostycznych zaburzeń snu (w różnych etapach snu występują wolne lub szybkie ruchy gałek ocznych).&lt;br /&gt;
Sygnał EOG można też wykorzystać do konstrukcji interfejsów [[http://dl.acm.org/citation.cfm?id=1740647]].&lt;br /&gt;
# Ruch oka sterowany jest za pomocą mięśni. W trakcie rejestracji Elektrookulogramu widoczne będą również wyładowania elektryczne związane z działaniem mięśni.&lt;br /&gt;
===Ćwiczenie I: Podstawowe własności sygnału EOG ===&lt;br /&gt;
Wykonaj pomiar Elektrokulogramu za pomocą dwóch par elektrod połączonych w montażu dwubiegunowym. &lt;br /&gt;
&amp;lt;!--* Umieść jedną z elektrod nieco przyśrodkowo i nieznacznie powyżej szpary powiekowej, drugą zaś a po przeciwległej stronie, tj. nieco poniżej szpary powiekowej. --&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przyjrzyj się na bieżąco w SVAROGu sygnałom w poniższych sytuacjach, a następnie zarejestruj odpowiadajće im sygnały aby dało się je przedstawić w prezentacji.&lt;br /&gt;
&lt;br /&gt;
* Jedną parę elektrod umieść poniżej i powyżej oka, drugą w pobliżu lewej i prawej skroni.&lt;br /&gt;
* Skonfiguruj program do rejestracji i przeglądania mierzonego sygnału w czasie rzeczywistym.&lt;br /&gt;
* Wykonaj ruch oczami w górę i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj ruch oczami w dół i opisz zarejestrowany sygnał.&lt;br /&gt;
* Wykonaj mrugnięcie i opisz zarejestrowany sygnał.&lt;br /&gt;
* Przeczytaj fragment tekstu, zaobserwuj efekty związane z ruchem sakadowym oka.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, rozważ efekty stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Ćwiczenie II ===&lt;br /&gt;
Powtórz ćwiczenie I, łącząc elektrody z monopolarnymi wejściami wzmacniacza, elektrodę odniesienia umieść na lewym płatku uszu lub wyrostku sutkowatym.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie II: dekoder sakad ===&lt;br /&gt;
Napisz program wyświetlający na macierzy 5x5 następujące sekwencje:&lt;br /&gt;
* kwadrat środkowy - kwadrat górny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat prawy - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat dolny - kwadrat środkowy&lt;br /&gt;
* kwadrat środkowy - kwadrat lewy - kwadrat środkowy&lt;br /&gt;
Zapisuj do pliku tekstowego czasy i kody poszczególnych sekwencji. Powtórz po kilkanaście sekwencji całości.&lt;br /&gt;
&lt;br /&gt;
Wyświetl te sygnały w programie napisanym samodzielnie, bez stosowania filtra grórnoprzepustowego.&lt;br /&gt;
&lt;br /&gt;
Zaprojektuj detektor, wykrywający, która sekwencja została wykonana. Przetestuj go na zebrnym sygnale off-line.&lt;br /&gt;
&lt;br /&gt;
===Ćwiczenie III: interfejs 'sakadowy' ===&lt;br /&gt;
Zrealizuj prosty system do analizy on-line ruchu gałki ocznej, modyfikując detektor z poprzedniego ćwiczenia. W najprostszej wersji system ma wypisywać w terminalu wykryty kierunek sakady.&lt;br /&gt;
 (http://laboratorium-eeg.braintech.pl/rozdz11.html)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
w tym celu:&lt;br /&gt;
==== Napisz moduł:====&lt;br /&gt;
* Korzystając detektora sekwencji napisanego w ramach ćwiczenia III napisz moduł wykrywający sekwencje w czasie rzeczywistym.  Niech Twój moduł wypisuje wynik detekcji na konsolę.  '''Opis korzystania i pisania modułów do  systemu OBCI znajduje się''' [[http://bci.fuw.edu.pl/wiki/Tutorials tutaj]]. W dużym skrócie to co należy zrobić to:&lt;br /&gt;
 &lt;br /&gt;
* W  katalogu domowym utwórz podkatalog: &lt;br /&gt;
 ~/obci/scenarios&lt;br /&gt;
* w katalogu tym umieść plik:&lt;br /&gt;
 eog.ini&lt;br /&gt;
powinien on zawierać następującą treść:&lt;br /&gt;
&amp;lt;source lang = 'text'&amp;gt;&lt;br /&gt;
[peers]&lt;br /&gt;
scenario_dir=&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.mx]&lt;br /&gt;
path=multiplexer-install/bin/mxcontrol&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.config_server]&lt;br /&gt;
path=control/peer/config_server.py&lt;br /&gt;
&lt;br /&gt;
;***********************************************&lt;br /&gt;
;***********************************************&lt;br /&gt;
[peers.amplifier]&lt;br /&gt;
path = drivers/eeg/cpp_amplifiers/amplifier_tmsi.py&lt;br /&gt;
;ponizsza sciezka pokazuje na plik zaierajacy nasze ustawienia parametrow wzmacniacza&lt;br /&gt;
config=~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
&lt;br /&gt;
[peers.analysis]&lt;br /&gt;
path=~/obci/analysis/eog_realtime.py&lt;br /&gt;
config=~/obci/analysis/eog_realtime.ini&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* W powyższym pliku zadeklarowaliśmy, że lokalne parametry dla wzmacniacza znajduję się w pliku:&lt;br /&gt;
 ~/obci/scenarios/eog_local_params.ini&lt;br /&gt;
zatem musimy ten plik wytworzyć i wypełnić go np. taką treścią:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
[local_params]&lt;br /&gt;
channel_names=gora;dol;lewa;prawa&lt;br /&gt;
active_channels=0;1;2;3&lt;br /&gt;
sampling_rate=256&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
* W pliku ze scenariuszem zadeklarowaliśmy też, że nasz moduł analizy danych znajduje się w pliku:&lt;br /&gt;
 ~/obci/analysis/eog_realtime.py&lt;br /&gt;
tak więc musimy ten plik stworzyć i tam właśnie wpisać algorytm detekcji. Dla zachowania konwencji w tym samym katalogu powinien znajdować się plik na ewentualne parametry dla modułu eog_realtime.py. Musi on się nazywać tak samo, tyle, że ma rozszerzenie .ini. Musimy więc wytworzyć pusty plik:  &lt;br /&gt;
 ~/obci/analysis/eog_realtime.ini&lt;br /&gt;
Ponieważ nasz algorytm musi on się komunikować z resztą systemu obci trzeba go opakować w poniższy kod-szkielet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import random, time, numpy&lt;br /&gt;
 &lt;br /&gt;
from multiplexer.multiplexer_constants import peers, types&lt;br /&gt;
from obci.control.peer.configured_multiplexer_server import ConfiguredMultiplexerServer&lt;br /&gt;
from obci.configs import settings, variables_pb2&lt;br /&gt;
from collections import deque&lt;br /&gt;
 &lt;br /&gt;
import obci.utils.openbci_logging as logger&lt;br /&gt;
&lt;br /&gt;
#LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;info&amp;quot;)&lt;br /&gt;
LOGGER = logger.get_logger(&amp;quot;sample_analysis&amp;quot;, &amp;quot;debug&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
class SampleAnalysis(ConfiguredMultiplexerServer):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;A class responsible for handling signal message and making proper decision.&lt;br /&gt;
    The class inherits from generic class for convinience - all technical stuff&lt;br /&gt;
    is being done in this super-class&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self, addresses):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Initialization - super() and ready() calls are required...&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        super(SampleAnalysis, self).__init__(addresses=addresses,&lt;br /&gt;
                                          type=peers.ANALYSIS)&lt;br /&gt;
        self.ready()&lt;br /&gt;
        LOGGER.info(&amp;quot;Sample analysis init finished!&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def handle_message(self, mxmsg):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;The only required function in the class&lt;br /&gt;
        that will be fired every time message is received&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if mxmsg.type == types.AMPLIFIER_SIGNAL_MESSAGE:&lt;br /&gt;
            # Got proper message, let`s unpack it ...&lt;br /&gt;
 &lt;br /&gt;
            # Messages are transmitted in bunches so lets define SampleVector&lt;br /&gt;
            # in order to unpack bunch of Sample messages ...&lt;br /&gt;
	    l_vect = variables_pb2.SampleVector()&lt;br /&gt;
            l_vect.ParseFromString(mxmsg.message)&lt;br /&gt;
 &lt;br /&gt;
            # Now we have message unpacked, lets iterate over every sample ...&lt;br /&gt;
            for s in l_vect.samples:&lt;br /&gt;
 &lt;br /&gt;
                # Every sample has two fields:&lt;br /&gt;
                # timestamp - system clock time of a moment of Sample`s creation&lt;br /&gt;
                # channels - a list of values - one for every channel&lt;br /&gt;
                LOGGER.debug(&amp;quot;Got sample with timestamp: &amp;quot;+str(s.timestamp))&lt;br /&gt;
 &lt;br /&gt;
                # One can copy samples to numpy array ...&lt;br /&gt;
&lt;br /&gt;
                a = numpy.array(s.channels) # w tym miejscu mamy w tablicy a &amp;quot;paczke&amp;quot; próbek (domyślnie 4próbki ) ze wszystkich zadeklarowanych kanalow &lt;br /&gt;
#################### TU TRZEBA WPISAC SWOJ KOD BUFOROWANIA i ANALIZY  ##############&lt;br /&gt;
                print a #na dobry poczatek wypiszmy probki&lt;br /&gt;
&lt;br /&gt;
####################################################################&lt;br /&gt;
 &lt;br /&gt;
                # Or just iterate over values ...&lt;br /&gt;
                for ch in s.channels:&lt;br /&gt;
                    LOGGER.debug(ch)&lt;br /&gt;
 &lt;br /&gt;
            # Having a new bunch of values one can fire some magic analysis and &lt;br /&gt;
            # generate decision ....&lt;br /&gt;
 &lt;br /&gt;
            # Below we have quite simple decision-maker - it generates a random&lt;br /&gt;
            # decision every ~100 samples-bunch&lt;br /&gt;
########## TU NA PODSTAWIE ANALLIZY PODEJMUJEMY DECYZJE I MOZEMY JA PRZEKAZAC DO RESZTY SYSTEMU OBCI ######################&lt;br /&gt;
########## W TYM PRZYKLADZIE JEST TO LOSOWA DECYZJA ##############&lt;br /&gt;
########## W TYM CWICZENIU WYSTARCZY JESLI WYPISZECIE DECYZJE NA EKRAN ###########&lt;br /&gt;
            if random.random() &amp;gt; 0.99:&lt;br /&gt;
                # Here we send DECISION message somewhere-to-the-system ...&lt;br /&gt;
                # It's up to scenario's configuration how the decision will be used ...&lt;br /&gt;
                # Eg. it might be used by LOGIC module to push some button in speller.&lt;br /&gt;
                self.conn.send_message(message = str(random.randint(0,7)), &lt;br /&gt;
                                       type = types.DECISION_MESSAGE, &lt;br /&gt;
                                       flush=True)&lt;br /&gt;
        else:&lt;br /&gt;
            LOGGER.warning(&amp;quot;Got unrecognised message type: &amp;quot;+str(mxmsg.type))&lt;br /&gt;
 &lt;br /&gt;
        # Tell the system 'I`ll not respond to this message, I`m just receiving'&lt;br /&gt;
        self.no_response()&lt;br /&gt;
 &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    # Initialize and run an object in order to have your analysis up and running&lt;br /&gt;
    SampleAnalysis(settings.MULTIPLEXER_ADDRESSES).loop()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Aby uruchomić nasz scenariusz trzeba wywołać:&lt;br /&gt;
 obci launch ~/obci/scenarios/eog.ini&lt;br /&gt;
* Zatrzymanie scenariusza robimy tak:&lt;br /&gt;
 obci kill eog&lt;br /&gt;
W tym momencie komunikaty ze wszystkich modułów wypisywane są na jednej konsoli. Przydatne jest korzystanie z obiektu 'LOGGER' zamiast funkcji 'print' - w konsoli mamy informację o źródle komunikatu i jego czasie.&lt;br /&gt;
&lt;br /&gt;
OpenBCI działa tak, że jeśli w jednym module pojawi się błąd, to wszystkie inne moduły są zamykane, stąd komunikat podobny do poniższego sugeruje, że w którymś module wystąpił błąd. W takim wypadku należy przejrzeć konsolę i wyszukać komunikat błędu. Niezbędne jest ustawienie bufora konsoli na 'nieograniczony' wykonując: Edycja-&amp;gt;Preferencje profilu-&amp;gt;Przewijanie-&amp;gt;Nieograniczone .&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
====Przetestuj moduł ====&lt;br /&gt;
* Umieść elektrody do rejestracji ruchu gałki ocznej jak w ćwiczeniu I i przetestuj działanie modułu. Miłej zabawy :-)&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7951</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7951"/>
		<updated>2019-02-21T13:53:16Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Pomiary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. &amp;lt;!--Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwszy kanał to próbki czasu wyrażone w [s] natomiast pozostałe kanały to dane z kolejnych sensorów TR, BR, TL, BL (górny prawy-TR, dolny prawy-BR, górny lewy-TL, dolny lewy-BL).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TR = wbr.get_samples()[0,:]&lt;br /&gt;
BR = wbr.get_samples()[1,:]&lt;br /&gt;
TL = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TR = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
TL = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of pressure'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7950</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7950"/>
		<updated>2019-02-21T13:53:03Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Pomiary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. &amp;lt;!--Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwszy kanał to próbki czasu wyrażone w [s] natomiast pozostałe kanały to dane z kolejnych sensorów TR, BR, TL, BL (górny prawy-TR, dolny prawy-BR, górny lewy-TL, dolny lewy-BL).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TR = wbr.get_samples()[0,:]&lt;br /&gt;
BR = wbr.get_samples()[1,:]&lt;br /&gt;
TL = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TR = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
TL = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of pressure'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7949</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7949"/>
		<updated>2019-02-21T13:51:20Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przygotowanie danych do analizy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwszy kanał to próbki czasu wyrażone w [s] natomiast pozostałe kanały to dane z kolejnych sensorów TR, BR, TL, BL (górny prawy-TR, dolny prawy-BR, górny lewy-TL, dolny lewy-BL).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TR = wbr.get_samples()[0,:]&lt;br /&gt;
BR = wbr.get_samples()[1,:]&lt;br /&gt;
TL = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci_readmanager.signal_processing import read_manager&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci_readmanager.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TR = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
TL = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of pressure'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_EEG/Potencja%C5%82y_wywo%C5%82ane&amp;diff=7896</id>
		<title>Pracownia EEG/Potencjały wywołane</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_EEG/Potencja%C5%82y_wywo%C5%82ane&amp;diff=7896"/>
		<updated>2018-10-25T12:08:42Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Synchronizacja występowania bodźców z sygnałem EEG */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Pracownia EEG|Pracownia EEG]] / Potencjały wywołane&lt;br /&gt;
&lt;br /&gt;
=Wstęp=&lt;br /&gt;
==Potencjały wywołane==&lt;br /&gt;
=== Wstęp ===&lt;br /&gt;
Potencjały wywołane EEG (ang. ''evoked potentials'', EP) są śladami odpowiedzi mózgu na bodźce. W przypadku MEG poprawnie mówi się o polach wywołanych (ang. ''evoked fields'', EF).&lt;br /&gt;
Zwykle reakcja ta jest mała (wyjątek stanowią [[Elektroencefalografia/Metody_analizy_sygnałów_EEG_-_analiza_w_dziedzinie_czasu |kompleksy K]]) i w zapisie pojedynczej realizacji reakcji na bodziec najczęściej niewidoczna wśród czynności pochodzącej od wielu innych procesów zachodzących w tym samym czasie w mózgu. &lt;br /&gt;
Ich wyodrębnienie z tak zwanego tła EEG/MEG, czyli manifestacji elektrycznej innych, trwających w tym samym czasie w mózgu procesów (aktywny prąd niezależny), wymaga w dniu dzisiejszym zapisu odpowiedzi na szereg powtórzeń tego samego bodźca (&amp;lt;xr id=&amp;quot;fig:EP&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Pierwsze potencjały wywołane pokazał pod koniec lat 40-tych Dawson (Dawson 1947) wykonując superpozycję pojedynczych realizacji na kliszy fotograficznej.&lt;br /&gt;
Z czasem skomplikowane urządzenia analogowe zastąpione zostały przez cyfrowe uśrednianie kolejnych fragmentów EEG, zsynchronizowanych według momentu wystąpienia bodźca, łatwo realizowane za pomocą komputera.&lt;br /&gt;
&lt;br /&gt;
[[Grafika:EP.png|thumb|640px|center|&amp;lt;figure id=&amp;quot;fig:EP&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
Uśrednianie potencjałów wywołanych. a) ciągły zapis EEG z wyróżnionymi momentami wystąpienia bodźca (w tym przypadku słuchowego) b) kilkadziesiąt kolejnych odcinków, wyciętych jako sekunda EEG od momentu wystąpienia kolejnych bodźców, ustawione jeden pod drugim c) uśredniony potencjał wywołany &amp;amp;mdash; widać m. in. załamek P300 ok. 300 milisekund po bodźcu]]&lt;br /&gt;
&lt;br /&gt;
Techniki te opierają się na założeniu, że zawarta w EEG odpowiedź mózgu na każdy z kolejnych bodźców jest niezmienna, a EEG odzwierciedlające pozostałe procesy traktowane jest jak nieskorelowany z nią proces stochastyczny. Zależnie od rodzaju potencjałów wywołanych, założenia te są mniej lub bardziej nieuzasadnione; podważa je choćby powszechnie znany efekt habituacji, polegający na osłabieniu późnych potencjałów wywołanych kolejnymi powtórzeniami bodźca.&lt;br /&gt;
&lt;br /&gt;
Istota potencjałów wywołanych jest przedmiotem otwartej dyskusji i dziesiątków prac, dotykających od lat podstawowych w tej dziedzinie pytań: czym jest potencjał wywołany, który widzimy w uśrednionym przebiegu? Czy naprawdę wynika z deterministycznie powtarzanej, jednakowej odpowiedzi pojawiającej się po każdym powtórzeniu bodźca niezależnie od &amp;amp;bdquo;tła&amp;amp;rdquo;, czy może wynika z reorganizacji faz tego właśnie &amp;amp;bdquo;tła&amp;amp;rdquo; EEG, czy może kombinacji tych dwóch efektów? Jest to wspaniałe pole dla zastosowań zaawansowanych metod modelowania i analizy sygnałów. W ostatnich latach powstają dziesiątki prac na ten temat, a od czasu do czasu również krytyczne artykuły wykazujące, że dotychczasowe odkrycia są raczej artefaktami stosowanych metod a nie wynikają z własności analizowanych danych (Yeung et al., 2004). Jak widać jest tu wciąż bardzo wiele do zrobienia, gdyż zrozumienie tego mechanizmu stoi na drodze do &amp;amp;bdquo;świętego Graala&amp;amp;rdquo;, którym w tej dziedzinie jest wyodrębnienie pojedynczych potencjałów wywołanych.&lt;br /&gt;
&lt;br /&gt;
Niezależnie od tego, w neurofizjologii klinicznej nazwą potencjał wywołany określa się krzywą widoczną po uśrednieniu odpowiedzi na kilkanaście do kilku tysięcy bodźców (Szelenberger 2000). Gromadzona od dziesięcioleci wiedza o behawioralnych i klinicznych korelatach potencjałów wywołanych opiera się na rozpoznawaniu w przebiegach uśrednionych tak zwanych załamków, czyli przejściowych wzrostów lub spadków potencjału (na przykład na &amp;lt;xr id=&amp;quot;fig:EP&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt; widać załamek P300). Nazwy załamków składają się zwykle z litery &amp;amp;bdquo;P&amp;amp;rdquo; (od ang. ''positive''), jeśli wychylenie jest dodatnie, lub &amp;amp;bdquo;N&amp;amp;rdquo; (od ang. ''negative''), jeśli wychylenie jest ujemne, oraz liczby. Uwaga: &lt;br /&gt;
* Nie ma niestety jednej ustalonej konwencji prezentacji potencjałów koniecznie trzeba więc zwracać uwagę na orientację wykresu, a wykonując wykres samemu - zamieszczać informację o orientacji kierunku dodatniego,gdyż kierunek dodatni może być wykresie skierowany do góry lub do dołu. &lt;br /&gt;
* Liczba następująca po N lub P określa przybliżoną liczbę milisekund od wystąpienia bodźca, czyli tak zwaną latencję. Nie można jednak ścisłego związku między tą liczbą a liczbą milisekund np. potencjał P300 w zależności od szczegółów paradygmatu doświadczalnego może wystąpić znacznie później. np. w eksperymentach językowych zdarza się że P300 występuje później niż N400 :-).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xr id=&amp;quot;fig:zalamki&amp;quot;&amp;gt;Rys. %i&amp;lt;/xr&amp;gt; przedstawia schematycznie najważniejsze załamki rozpoznawane w potencjałach słuchowych, czyli wywoływanych bodźcem dźwiękowym. Dla potencjałów wzrokowych i somatosensorycznych istnieją podobne klasyfikacje.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Grafika:Zalamki.png|thumb|320px|right|&amp;lt;figure id=&amp;quot;fig:zalamki&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
Orientacyjny schemat załamków rozpoznawanych w słuchowych potencjach wywołanych, na podstawie (Szelenberger 2000). Skala czasu logarytmiczna. Najszybsze (do 12 ms) składowe egzogenne to potencjały pniowe (BAEP), oznaczane jako fale I-VII. Litery &amp;amp;bdquo;P&amp;amp;rdquo; i &amp;amp;bdquo;N&amp;amp;rdquo; oznaczają dodatnie i ujemne wychylenia związane z dalszymi załamkami]]&lt;br /&gt;
&lt;br /&gt;
Najszybsze (czyli o najmniejszej latencji) składowe to potencjały egzogenne, odzwierciedlające wstępne fazy przekazu informacji. W potencjałach słuchowych są to potencjały pnia (ang. ''brainstem auditory evoked potentials'', BAEP), składające się z siedmiu fal występujących pomiędzy 1 a 12 ms od bodźca. Są one generowane np. w nerwie słuchowym czy pniu mózgu, i wykorzystywane w klinicznej diagnostyce integralności dróg słuchowych. Podobnie jak inne wczesne potencjały o latencjach poniżej 100 ms, są praktycznie niezależne od stanu uwagi.&lt;br /&gt;
&lt;br /&gt;
Po potencjałach o średniej latencji (między 12 a 50 ms) zaczynają się późne potencjały słuchowe, odzwierciedlające bardziej złożone reakcje na bodziec. Na przykład amplituda załamka N100 wzrasta w stanie skupienia uwagi czy pobudzenia emocjonalnego. Około 200 milisekund po bodźcu pojawia się załamek odzwierciedlający modną ostatnio ''falę niezgodności'' (ang. ''mismatch negativity''). Jest on wyrazem nieświadomej i automatycznej reakcji na zmianę bodźca &amp;amp;mdash; na przykład na pojawiające się stosunkowo rzadko dźwięki o innej częstości w serii dźwięków o jednakowej wysokości. Wreszcie pierwszy i najpopularniejszy całkowicie endogenny załamek to P300, pojawiający się po rozpoznaniu bodźca oczekiwanego, na którym skupiamy uwagę: na przykład, jeśli w serii pojawiających się losowo liter mamy zliczać wystąpienia jednej z nich, to na średniej odpowiedzi na pojawienie się tej litery pojawi się załamek P300.&lt;br /&gt;
&lt;br /&gt;
=== Uśrednianie w dziedzinie czasu ===&lt;br /&gt;
Jak już było wspomniane powyżej podstawową techniką stosowaną do analizy potencjałów wywołanych jest uśrednianie wielu realizacji odpowiedzi na bodziec wyrównanych względem jakiegoś charakterystycznego zdarzenia, np. momentu podania bodźca albo momentu behawioralnej reakcji na bodziec (np. wciśnięcie przycisku). Podejście to bazuje na trzech założeniach:&lt;br /&gt;
* Reakcja jest czasowo związana z bodźcem. Tzn. w kolejnych realizacjach występuje ona zawsze z tym samym opóźnieniem.&lt;br /&gt;
* Reakcja na bodziec skutkuje zawsze pojawieniem się w sygnale składowej o stałym kształcie (mówimy o stałej morfologii).&lt;br /&gt;
* Spontaniczna czynność EEG &amp;amp;mdash; ta która nie dotyczy przetwarzania interesującego nas bodźca &amp;amp;mdash; jest niezależnym, stacjonarnym szumem o średniej zero.&lt;br /&gt;
&lt;br /&gt;
Zgodnie z powyższymi założeniami mierzony w ''i''-tej realizacji sygnał można wyrazić jako:&lt;br /&gt;
: &amp;lt;math&amp;gt;x_i(t) = s(t) + n_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
Uśrednianie po ''N'' realizacjach daje:&lt;br /&gt;
: &amp;lt;math&amp;gt;\bar x (t) = \frac{1}{N} \sum_{i=1}^N x_i(t) = \frac{1}{N} \left(N s(t) + \sum_{i=1}^N n_i(t) \right) &amp;lt;/math&amp;gt;&lt;br /&gt;
Wartość oczekiwana średniego sygnału wynosi:&lt;br /&gt;
: &amp;lt;math&amp;gt;\mathrm{E}\left[ \bar x(t) \right] = s(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
gdyż dla szumu o średniej zero mamy:&lt;br /&gt;
: &amp;lt;math&amp;gt;\mathrm{E}\left[\frac{1}{N} \sum_{i=1}^N n_i(t)\right] = 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
Wariancja &amp;lt;math&amp;gt;\bar x(t)&amp;lt;/math&amp;gt; wynosi:&lt;br /&gt;
: &amp;lt;math&amp;gt;\sigma^2_{\bar x(t)} = \mathrm{E} \left[  \left( \frac{1}{N} \sum_{i=1}^N n_i(t)\right)^2 \right] \approx \frac{1}{N} \sigma^2_{n(t)}&amp;lt;/math&amp;gt;&lt;br /&gt;
gdyż &amp;lt;math&amp;gt;s(t)&amp;lt;/math&amp;gt; jest deterministyczne. &lt;br /&gt;
&lt;br /&gt;
Dla potencjałów pojawiających się w pierwszych kilkudziesięciu milisekundach po bodźcu model ten można uznać za poprawny, gdyż wykazują one zależność głównie od parametrów fizycznych bodźca. Dla późniejszych składowych staje się on coraz bardziej wątpliwy ze względu na występujące korelacje ze stanem (np. uwagi) badanego.&lt;br /&gt;
&lt;br /&gt;
Dla późniejszych składowych można by postulować bardziej ogólną wersję modelu potencjału wywołanego:&lt;br /&gt;
: &amp;lt;math&amp;gt;x_i(t) = s_i(t) + n_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
Ten model uwidacznia, że do opisu potencjału wywołanego potrzebna jest nie tylko średnia, ale i wyższe momenty rozkładu (np. drugi moment centralny czyli wariancja).&lt;br /&gt;
&lt;br /&gt;
====Wariancja w przypadku szumu skorelowanego ====&lt;br /&gt;
W poprzednim paragrafie pokazaliśmy, że w przypadku niezależnego szumu wariancja uśrednionego sygnału (w danej chwili czasu) maleje jak  &amp;lt;math&amp;gt;\frac{1}{N}&amp;lt;/math&amp;gt;. Jednak w przypadku gdy kolejne próbki szumu są skorelowane (np. występuje silna aktywność rytmiczna alfa) sytuacja się komplikuje. Intuicyjnie łatwo możemy to sobie wyobrazić w granicznym przypadku. Załóżmy, że tło dla  potencjałów o stałej morfologii   stanowi sinusoida. Jeśli będziemy podawać bodźce w odstępach będących wielokrotnością okresu tej sinusoidy to w uśrednianych fragmentach sygnału owa sinusoida jest tak samo powtarzalna jak badany potencjał i uśrednianie nie prowadzi do poprawy stosunku amplitudy sygnału do amplitudy tła. &lt;br /&gt;
&lt;br /&gt;
Stopień zależności pomiędzy próbkami można zmierzyć przy pomocy funkcji autokorelacji. &lt;br /&gt;
Jeśli funkcję autokorelacji przybliżymy przez:&lt;br /&gt;
: &amp;lt;math&amp;gt;R_{xx}(\tau) = \sigma^2 \exp(-\beta |\tau|) \cos(2 \pi f_0 \tau)&amp;lt;/math&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;\sigma^2&amp;lt;/math&amp;gt; jest wariancją szumu, &amp;lt;math&amp;gt;f_0&amp;lt;/math&amp;gt; jest średnią częstością aktywności rytmicznej, &amp;lt;math&amp;gt;\beta/ \pi&amp;lt;/math&amp;gt; jest szerokością pasma tej czynności, zaś &amp;lt;math&amp;gt;\tau&amp;lt;/math&amp;gt; opóźnieniem, to wariancję potencjału wywołanego można wyrazić jako&amp;lt;!-- \cite{Spekreijse_1976}--&amp;gt;:&lt;br /&gt;
: &amp;lt;math&amp;gt;\sigma^2_{\bar x(t)} = \frac{\sigma^2}{N} \left[ \frac{1-\exp(-2 \beta T)}{1 - 2 \exp(- \beta T) \cos(2 \pi f_0 T) +\exp(-2 \beta T)} \right]&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; jest odstępem między bodźcami. &lt;br /&gt;
Widać stąd, że obecność czynności rytmicznej w tle wpływa na stosunek sygnału do szumu. Z powyższego równania widać, że stosunek wariancji dąży do &amp;lt;math&amp;gt;\frac{\sigma^2}{N}&amp;lt;/math&amp;gt; gdy &amp;lt;math&amp;gt;\beta T&amp;lt;/math&amp;gt; staje się duże.  &lt;br /&gt;
&lt;br /&gt;
Periodyczna stymulacja może ponadto prowadzić do wzbudzenia czynności rytmicznej o częstości równej częstości pobudzania bądź jej harmonicznej.&lt;br /&gt;
&lt;br /&gt;
===Wariancja latencji===&lt;br /&gt;
&lt;br /&gt;
Jedną z form zmienności potencjału wywołanego w pojedynczych realizacjach jest wariancja latencji. &lt;br /&gt;
[[Grafika:Wariancja_latencji.png|thumb|500px|right|&lt;br /&gt;
Czerwona linia: Uśrednianie 100 potencjałów wywołanych o latncjach z rozkładu normalnego N(300,30 ), Niebieskie linie: przykładowe pojedyncze realizacje wzięte do średniej]]&amp;lt;!--# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show ,subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
 &lt;br /&gt;
def fun(t,lat=100):&lt;br /&gt;
    return np.exp(-(t-lat)**2/(2*30**2))&lt;br /&gt;
Fs = 1&lt;br /&gt;
N = 100&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
f = np.zeros((N,700))&lt;br /&gt;
f_sr = np.zeros(t.shape)&lt;br /&gt;
for i in range(N):&lt;br /&gt;
    f[i,:] = fun(t,lat = 300 + 30* np.random.randn())&lt;br /&gt;
for i in range(3):&lt;br /&gt;
    plot(t,f[i,:], 'b')&lt;br /&gt;
plot(t,f.mean(0),'r')&lt;br /&gt;
show()--&amp;gt;&lt;br /&gt;
Zmienność latencji prowadzi do:&lt;br /&gt;
* zmniejszenia amplitudy &amp;lt;math&amp;gt;\bar x&amp;lt;/math&amp;gt;&lt;br /&gt;
* wzrostu rozciągłości czasowej załamka&lt;br /&gt;
&lt;br /&gt;
O tych konsekwencjach zmienności latencji należy w szczególności pamiętać porównując średnie potencjały uzyskane w różnych warunkach eksperymentalnych. Gdy zauważymy, że średnie potencjały różnią się amplitudą należy rozważyć możliwość, że w istocie warunki eksperymentalne wpływają na różnice w wariancji latencji. &lt;br /&gt;
&lt;br /&gt;
Naturalne jest, że zmienność latencji jest bardziej widoczna w przypadku załamków trwających krótko niż w przypadku załamków trwających długo. Wariancja latencji rożnie wraz z jej wartością, stąd wśród późnych składowych potencjałów wywołanych nie obserwuje się komponentów krótkotrwałych.&lt;br /&gt;
====Uśrednianie metodą Woody'ego ====&lt;br /&gt;
&lt;br /&gt;
Model potencjału ze zmienną latencją i sposób na jego efektywniejsze uśrednianie zaproponował Woody (1967). Model ten zakłada, że w każdej realizacji występuje komponent addytywny &amp;lt;math&amp;gt;s_i(t)\;&amp;lt;/math&amp;gt;, który co do kształtu jest stały, a pomiędzy realizacjami różni się tylko latencją:&lt;br /&gt;
: &amp;lt;math&amp;gt; s_i(t) = s(t +\Delta t_i)\;&amp;lt;/math&amp;gt;&lt;br /&gt;
Woody zaproponował aby &amp;lt;math&amp;gt;\Delta t_i\;&amp;lt;/math&amp;gt; szacować na podstawie maksimum funkcji korelacji wzajemnej pomiędzy ''i''-tą realizacją a wzorcem. W pierwszym kroku wzorcem jest średni potencjał uzyskany przez proste uśrednienie realizacji.  Następnie w sposób iteracyjny dokonuje się:&lt;br /&gt;
* poprawek w wyrównaniu poszczególnych realizacji,&lt;br /&gt;
* obliczenia nowego wzorca poprzez uśrednienie realizacji po korekcie wyrównania,&lt;br /&gt;
* obliczenia nowych poprawek do wyrównania realizacji.&lt;br /&gt;
&lt;br /&gt;
===Habituacja ===&lt;br /&gt;
Zmienność w odpowiedziach na kolejno występujące po sobie bodźce można podzielić na komponent stochastyczny i deterministyczny. Komponent deterministyczny odzwierciedla zmianę czułości  układu nerwowego  na kolejne bodźce. Nowy bodziec często wywołuje reakcje pobudzenia widoczną w wielu parametrach takich jak przewodnictwo skóry, rytm serca i reaktywność kory mózgowej. Powszechnie obserwowanym zjawiskiem jest spadek reaktywności na powtarzające się bodźce zwany habituacją. Niekiedy obserwuje się także zjawisko przeciwne &amp;amp;mdash; wzrost reaktywności na bodziec &amp;amp;mdash; zwane sensytyzacją. &lt;br /&gt;
&lt;br /&gt;
Klasycznym sposobem na badanie tych zjawisk w potencjałach wywołanych jest uśrednianie w podzbiorach lub  uśrednianie blokowe. Wymaga ono  zmiany paradygmatu rejestracji danych. Załóżmy, że interesującym nas bodźcem jest błysk światła. Chcemy zaobserwować ewentualne zmiany amplitudy i latencji w ciągu 100 potencjałów będących reakcją na błysk powtarzający się co 500 ms.&lt;br /&gt;
====Uśrednianie w podzbiorach ====&lt;br /&gt;
W metodzie tej musimy założyć, że proces habituacji jest powolny, tzn. zmiany pomiędzy kolejnymi reakcjami są bardzo małe. W takim przypadku możemy podzielić długą serię bodźców na ciąg pod-serii i uśrednienie przeprowadzić dla każdej pod-serii osobno.&lt;br /&gt;
[[Plik:Usrednianie_podzbiory.svg‎|640px|thumb|center|Ilustracja uśredniania w podzbiorach]]&lt;br /&gt;
&lt;br /&gt;
====Uśrednianie blokowe====&lt;br /&gt;
W tym celu eksperyment wykonujemy w wielu seriach. Jedna seria składa się ze 100 błysków powtarzanych co 500 ms.  Po serii następuje przerwa trwająca np. 5 s (długość przerwy wyraża nasze oszacowanie czasu potrzebnego na zanik habituacji). Po przerwie seria jest powtarzana. Powtórzeń serii wykonujemy ''N''.&lt;br /&gt;
Następnie uśredniamy fragmenty sygnałów odpowiadające sobie w kolejnych seriach. &lt;br /&gt;
&lt;br /&gt;
W tym paradygmacie zakładamy, że każda seria rejestrowana jest w tych samych warunkach. Zaniedbujemy efekty związane ze zmęczeniem i zmianami w np. stopniu koncentracji badanego.&lt;br /&gt;
[[Plik:Usrednianie blokowe.svg|Usrednianie blokowe.svg|640px|thumb|center|Ilustracja uśredniania w blokach]]&lt;br /&gt;
&lt;br /&gt;
===Załamki w krzywej potencjału wywołanego vs ukryte komponenty===&lt;br /&gt;
Komponenta potencjału wywołanego to bardzo ważne ale jednocześnie źle określone pojęcie. Krzywa otrzymana w wyniku uśredniania potencjałów wywołanych przedstawia serię załamków dodatnich i ujemnych, ale trzeba być świadomym, że ten przebieg napięcia rejestrowany przez elektrody przedstawia tak naprawdę sumę potencjałów pochodzących od wielu dość niezależnie działających źródeł w mózgu. Przyczynek pochodzący od jednego funkcjonalnego źródła będziemy określać jako komponentę. &lt;br /&gt;
&lt;br /&gt;
Komentarza wymaga też pojęcie źródła funkcjonalnego. Czynność elektryczną synchronicznie działających neuronów piramidalnych w określonym fragmencie kory mózgowej z pewnej odległości można przybliżyć potencjałem dipola prądowego. Taki aktywny fragment kory stanowi źródło dające przyczynek do mierzonego na powierzchni głowy potencjału. W najprostszej sytuacji taki przyczynek może być obserwowany jako komponenta. Mózg jest jednak obiektem niezwykle złożonym i gęsto połączonym. Wiele obszarów korowych może być funkcjonalnie połączonych i aktywowanych synchronicznie w celu realizacji określonego zadania &amp;amp;mdash; o takim funkcjonalnym zespole też możemy myśleć jako o pojedynczym źródle, choć może ono mieć złożoną strukturę przestrzenną. Często zatem myślimy o komponentach ukrytych potencjału wywołanego jako o aktywności takich funkcjonalnych zespołów. &lt;br /&gt;
&lt;br /&gt;
Po tym wstępie widać już chyba, że do zrozumienia co dzieje się w czasie reakcji na bodziec, którą obserwujemy w potencjale wywołanym, bardziej pożądane byłoby badanie komponent ukrytych niż poszczególnych załamków krzywej potencjału wywołanego, która stanowi ważoną sumę owych komponentów. Zanim przejdziemy do omówienia technik służących &amp;amp;bdquo;wyłuskiwaniu&amp;amp;rdquo; komponent prześledźmy kilka symulacji i wnioski z nich płynące.&lt;br /&gt;
&lt;br /&gt;
==== Załamki i komponenty nie są tym samym.====&lt;br /&gt;
Tę samą krzywą można otrzymać na nieskończenie wiele sposobów  przez sumowanie rożnych kombinacji domniemanych komponentów. Przykładowy rysunek pokazuje, jak tę samą krzywą można złożyć z dwóch rożnych zestawów komponentów (kod wytwarzający przykładową symulację pokazany jest poniżej).&lt;br /&gt;
[[Plik:Sumowanie_komponentow1.png|center|thumb|600px| Panel a) przedstawia hipotetyczną krzywą ERP, panel b) jedna z możliwych dekompozycji sygnału w panelu a), panel c) inna możliwa dekompozycja sygnału z panelu a) ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show ,subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
&lt;br /&gt;
Fs = 1&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
&lt;br /&gt;
C1 = np.exp(-(t-100)**2/(2*30**2))&lt;br /&gt;
C2 = np.exp(-(t-200)**2/(2*50**2))&lt;br /&gt;
C3 = np.exp(-(t-350)**2/(2*100**2))&lt;br /&gt;
ERP = 0.5*C1-C2+C3&lt;br /&gt;
&lt;br /&gt;
C2p = np.concatenate((C2[0:200], np.ones(30), C2[200:700-30] ))&lt;br /&gt;
C3p = ERP - 0.5*C1 + C2p&lt;br /&gt;
ERP_v2 = 0.5*C1-C2p+C3p&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,1)&lt;br /&gt;
plot(t,ERP, t[::10],ERP_v2[::10],'g.')&lt;br /&gt;
ylabel('a)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,2)&lt;br /&gt;
plot(t,0.5*C1,t,-C2,t,C3)&lt;br /&gt;
ylabel('b)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,3)&lt;br /&gt;
plot(t,0.5*C1,t,-C2p,t,C3p)&lt;br /&gt;
ylabel('c)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Zmiana jednej komponenty może powodować zmiany w amplitudzie i latencji więcej niż jednego załamka.====&lt;br /&gt;
Poniższy rysunek przedstawia sytuację gdy zmiana amplitudy jednego komponentu może znacząco wpływać na amplitudę i latencję innych załamków.&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sumowanie_komponentow2.png|center|thumb|768px| Panel a) przedstawia dwie hipotetyczne krzywe ERP, panel b) panel b i c komponenty z których powstały owe krzywe. Zmiana amplitudy komponentu oznaczonego kolorem powoduje zmianę amplitudy oznaczonych załamków ale także zmianę latencji wcześniejszego załamka. ]]&lt;br /&gt;
Poniżej kod odtwarzający powyższy przykład:&lt;br /&gt;
&amp;lt;source lang = python&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show, subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
&lt;br /&gt;
Fs = 1&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
&lt;br /&gt;
C1 = np.exp(-(t-100)**2/(2*30**2))&lt;br /&gt;
C2 = np.exp(-(t-200)**2/(2*50**2))&lt;br /&gt;
C3 = np.exp(-(t-350)**2/(2*100**2))&lt;br /&gt;
ERP1 = 0.5*C1-C2+C3&lt;br /&gt;
ERP2 = 0.5*C1-C2+1.5*C3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,1)&lt;br /&gt;
plot(t,ERP1,'b', t,ERP2,'g')&lt;br /&gt;
plot(t[np.argmin(ERP1)],np.min(ERP1),'r.' )&lt;br /&gt;
plot(t[np.argmax(ERP1)],np.max(ERP1),'m.' )&lt;br /&gt;
plot(t[np.argmin(ERP2)],np.min(ERP2),'r.' )&lt;br /&gt;
plot(t[np.argmax(ERP2)],np.max(ERP2),'m.' )&lt;br /&gt;
&lt;br /&gt;
ylabel('a)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,2)&lt;br /&gt;
plot(t,0.5*C1,'k',t,-C2,'k',t,C3,'b')&lt;br /&gt;
ylabel('b)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,3)&lt;br /&gt;
plot(t,0.5*C1,'k',t,-C2,'k',t,1.5*C3,'g')&lt;br /&gt;
ylabel('c)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Instrukcje do ćwiczeń =&lt;br /&gt;
&lt;br /&gt;
==Zadanie 1: uśrednianie symulowanych sygnałów==&lt;br /&gt;
w tym ćwiczeniu chcemy pokazać efekty:&lt;br /&gt;
# uśredniania sygnałów związanych fazowo z bodźcem i nieskorelowanych z bodźcem / wpływ liczby realizacji,&lt;br /&gt;
# uśredniania sygnałów z fluktuacją latencji,&lt;br /&gt;
# wpływ filtrów o różnych funkcjach odpowiedzi impulsowej na morfologię uśrednionego potencjału.&lt;br /&gt;
&lt;br /&gt;
===Sygnały testowe===&lt;br /&gt;
Proszę zaimplementować funkcje generujące następujące przebiegi czasowe (oznaczenia: ''F&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;'' &amp;amp;mdash; częstość próbkowania, ''T'' &amp;amp;mdash; czas trwania w sekundach, [[%C4%86wiczenia_1#Sygna.C5.82y_testowe|analogicznie do tego]]):&lt;br /&gt;
* sinusoida o zadanej częstości ''f'' i fazie &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt;: &amp;lt;tt&amp;gt;y = sin(f, phi, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* funkcja Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_1(t0, sigma, Fs, T) &amp;lt;/tt&amp;gt;&lt;br /&gt;
: &amp;lt;math&amp;gt;g_1(t) = \exp\left(-\frac{(t-t_0)^2}{2 \sigma^2}\right)&amp;lt;/math&amp;gt;,&lt;br /&gt;
* pochodną funkcji Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_2(t0, sigma, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* połowę funkcji Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_3(t0, sigma, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
: &amp;lt;math&amp;gt;g_{3}(t) = \left\{ &lt;br /&gt;
\begin{array}{lll}&lt;br /&gt;
0 &amp;amp; \mathrm{dla}&amp;amp; t&amp;lt;t_0 \\&lt;br /&gt;
\exp\left(-\frac{(t-t_0)^2}{2 \sigma^2}\right)&amp;amp; \mathrm{dla}&amp;amp; t \ge t_0  &lt;br /&gt;
\end{array}&lt;br /&gt;
\right. &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W dalszych zadaniach tej sekcji przyjmiemy:&lt;br /&gt;
* ''T'' = 1 s,&lt;br /&gt;
* ''F&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;'' = 128 Hz,&lt;br /&gt;
* ''t''&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; = 0,3 s,&lt;br /&gt;
* &amp;amp;sigma; = 0,02 s.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu addytywnym: sygnał + szum===&lt;br /&gt;
Dla funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; i &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;  wykonaj ''N'' symulacji sygnału opisanego daną funkcją z dodanym szumem gaussowskim (&amp;lt;tt&amp;gt;numpy.random.randn&amp;lt;/tt&amp;gt;). Zaobserwuj zmianę wariancji uśrednianego sygnału wraz z ''N''.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu addytywnym: sygnał + szum + niezależna czynność rytmiczna===&lt;br /&gt;
Powtórz poprzednie symulacje dokładając w każdej realizacji sinusoidę o losowo wybranej fazie. Symulacje wykonaj dla różnych częstości sinusoidy, takich których połówka okresu zbliżona jest do szerokości funkcji Gaussa, oraz znacząco od niej różnych.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu z resetem fazy===&lt;br /&gt;
Zbuduj sygnał składający się z dwóch fragmentów sinusoidy o częstości ''f'': &lt;br /&gt;
* pierwszy fragment ma losową fazę,&lt;br /&gt;
* drugi fragment ma fazę równą 0.&lt;br /&gt;
Wykonaj ''N'' realizacji takiego sygnału, przy czym każda realizacja ma częstość losowaną z rozkładu Gaussa o średniej 10 i pewnej wariancji (czyli &amp;lt;math&amp;gt;f \in \mathrm{N}(10,\sigma)&amp;lt;/math&amp;gt;). &lt;br /&gt;
Uśrednij otrzymane realizacje. Zaobserwuj zależność średniej od ilości uśrednianych realizacji i od wariancji częstości.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie potencjału z fluktuacją latencji===&lt;br /&gt;
Wygeneruj sygnały składające się z funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt; z fluktuującą latencją, tzn. z wartością &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; pochodzącą z jakiegoś rozkładu prawdopodobieństwa. U nas dla ustalenia uwagi niech będzie to rozkład Gaussa. Wykonaj zestaw symulacji obrazujący zależność od ilości realizacji i od wielkości fluktuacji, mierzonej przez wariancję rozkładu. Czy jest związek pomiędzy wariancją fluktuacji &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; a szerokością załamków?&lt;br /&gt;
&lt;br /&gt;
===Wpływ filtrów===&lt;br /&gt;
# Zaprojektuj następujące filtry (przyjmij częstość próbkowania 128 Hz):&lt;br /&gt;
#* dolnoprzepustowy: Butterwortha z częstością odcięcia: 30, 40, 50 Hz, i rzędach od 1 do 5 (funkcja butter w module scipy.signal),&lt;br /&gt;
#* górnoprzepustowy: Butterwortha z częstością odcięcia: 0,1, 0,5, 2 i 5 Hz, i rzędach od 1 do 5,&lt;br /&gt;
#* notch: Czybyszewa II rodzaju z pasmem zaporowym ustawionym na 50 Hz, i rzędach od 1 do 3 (funkcja cheby2),&lt;br /&gt;
# Zbadaj funkcję odpowiedzi impulsowej i funkcję przenoszenia tych filtrów (w skali dB). Zaobserwuj jak długa jest odpowiedź impulsowa i jak daleko od częstości odcięcia zaburzone jest pasmo przenoszenia.&lt;br /&gt;
# Zastosuj powyższe filtry do funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;. Filtrowanie przeprowadź w jedną (lfilter) oraz w dwie strony (filtfilt). Zaobserwuj związek między zniekształceniem wprowadzanym przez filtr a funkcją odpowiedzi impulsowej filtru.&lt;br /&gt;
# W ćwiczeniu tym posłuż się symulowanymi sygnałami uzyskanymi z modelu addytywnego: &amp;amp;bdquo;sygnał+szum&amp;amp;rdquo;. Dla funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;  wykonaj ''N'' = 60 realizacji sygnału opisanego daną funkcją z dodanym szumem gaussowskim (&amp;lt;tt&amp;gt;numpy.random.randn&amp;lt;/tt&amp;gt;). Każdą z realizacji przefiltruj, a następnie uśrednij uzyskane sygnały.&lt;br /&gt;
&lt;br /&gt;
==Zadanie 2: rejestracje i analiza potencjałów wzrokowych==&lt;br /&gt;
&lt;br /&gt;
===Synchronizacja występowania bodźców z sygnałem EEG===&lt;br /&gt;
&lt;br /&gt;
Rejestracja potencjałów wywołanych jest przykładem pomiaru czynności elektrycznej mózgu w odpowiedzi na określony bodziec. W przypadku tego rodzaju pomiarów konieczna jest synchronizacja momentu wystąpienia bodźca z sygnałem EEG. Wzmacniacze do pomiaru czynności elektrycznej mózgu wyposażone są w specjalne wejścia, na które można podawać sygnał odpowiadający pojawianiu się bodźca. Jak pamiętamy z zeszłego semestru, wejście to (jak i podawany na nie sygnał) nazywamy trigerem (ang. ''trigger'' &amp;amp;mdash; spust, cyngiel, wyzwalacz). W najprostszym przypadku, bodziec moglibyśmy wyświetlać na monitorze komputerowym, a sygnał związany z jego wystąpieniem wysyłać przez któryś z portów komputera (LPT, COM) na wzmacniacz EEG. Niestety, obecnie dostępne i popularne systemy operacyjne, takie jak Windows czy Linux nie są systemami czasu rzeczywistego (http://pl.wikipedia.org/wiki/System_operacyjny_czasu_rzeczywistego). Od momentu wyświetlania bodźca na ekranie, do pojawiania się sygnału odpowiednim porcie komputerowym może upłynąć kilkadziesiąt milisekund i co gorsza czas ten zwykle jest losowy. W przypadku gdy wzmacniacz próbkuje sygnał z częstością 1000 Hz, moment wystąpienia bodźca możemy określić z dokładnością 1 ms, jednakże wspomniane opóźnienia w systemie operacyjnym uniemożliwiają to. Ponadto, jak dowiedzieliśmy się w rozdziale wstępnym [http://brain.fuw.edu.pl/edu-wiki/action/edit/EEG:Potencja%C5%82y_wywo%C5%82ane?section=T-1], pierwsze załamki związane z potencjałami wywołanymi pojawiają się już 10 ms po wystąpieniu bodźca. W związku z tym, losowe, rzędu kilkudziesięciu milisekund opóźnienia sygnału określającego moment pojawienia się bodźca względem jego rzeczywistego wystąpienia są niedopuszczalne.&lt;br /&gt;
Istnieją pewne techniki programowania, dzięki którym opisywane opóźnienia można zmniejszyć, jednakże są one bardzo trudne  do realizacji. Ponadto, standardowe porty komputera, takie jak LPT, czy COM zostały zaprojektowane przede wszystkim do sterowania urządzeniami zewnętrznymi, a nie ich zasilania. Przykładowo, jedna linia portu drukarkowego (LPT) może być obciążona prądem nie większym niż 5 mA, podczas gdy do zapalenie zwykłej diody LED potrzeba około 10 mA. Taki pobór prądu możliwy jest do uzyskania z portu USB, jednakże  jest on  wyjątkowo trudny do oprogramowania.  &lt;br /&gt;
W celu ominięcia powyższych niedogodności w Zakładzie Fizyki Biomedycznej UW w przeprowadzanych eksperymentach wykorzystywane są  mikrokontrolery [http://pl.wikipedia.org/wiki/Mikrokontroler], w szczególności ATmega16 i ATmega32.  Mikrokontrolery te wyposażone są w procesory o architekturze RISC [http://pl.wikipedia.org/wiki/RISC] i mocy obliczeniowej porównywalnej z szeroko stosowanym kiedyś w komputerach ZX Spectrum, Commodore, Amiga i Atari procesorem Z80. Oprócz jednostki centralnej mikrokontrolery zawierają   stałą pamięć FLASH przeznaczoną do przechowywania kodu programu, pamięć  RAM i pamięć EEPROM, liczniki 8- i 16-bitowe, komparatory, przetworniki analogowo-cyfrowe, porty wejścia/wyjścia, łącze RS232 (popularnie nazywane portem szeregowym) i układy przerwań.&lt;br /&gt;
&lt;br /&gt;
Mikrokontrolery wchodzące w skład zestawów pomiarowych na Pracowni EEG zawierają program, który umożliwia komunikację z nimi poprzez port szeregowy. Obecnie, komputery są coraz rzadziej wyposażane w porty szeregowe. Standard komunikacji RS-232, opracowany w 1962 roku  nadal jest jednak popularny i często wykorzystywany do komunikacji miedzy urządzeniami.  W celu połączenia komputera posiadającego tylko porty USB z mikrokontrolerem zastosowano przejściówkę USB/RS-232. &lt;br /&gt;
&lt;br /&gt;
Jak każde urządzenie w systemie Linuks, przejściówka USB/RS-232 widoczna jest jako plik, znajdujący się w katalogu &amp;lt;tt&amp;gt;/dev&amp;lt;/tt&amp;gt;. Nazwy plików obsługujących urządzenia szeregowe to &amp;lt;tt&amp;gt;ttyXY&amp;lt;/tt&amp;gt;, gdzie &amp;lt;tt&amp;gt;XY&amp;lt;/tt&amp;gt; to kolejny numer przydzielony do urządzenia szeregowego.&lt;br /&gt;
Do komunikacji komputera z mikroknotrolerem  w Zakładzie Fizyki Medycznej UW została napisana prosta biblioteka.  Jej użycie jest następujące:&lt;br /&gt;
* Po podłączeniu przejściówki USB/RS232 do komputera mikrokontrolera sprawdź jaki plik w katalogu &amp;lt;tt&amp;gt;/dev&amp;lt;/tt&amp;gt; został utworzony i przydzielony do urządzenia. &lt;br /&gt;
* Zaimportuj bibliotekę do komunikacji z mikrokontrolerem: &lt;br /&gt;
: &amp;lt;tt&amp;gt;import SerialPort as SP&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Otwórz plik powiązany z urządzeniem zewnętrznym:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp = SP.SerialPort(nazwa_pliku) &amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.open()&amp;lt;/tt&amp;gt;&lt;br /&gt;
gdzie przykładowa nazwa pliku wynosi &amp;lt;tt&amp;gt;/dev/ttyUSB0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Po włączeniu zasilania mikrokontrolera, diody podłączone do niego i wykorzystywane w eksperymencie z potencjałami wywołanymi będą zapalone. Następujące polecenie zgasi obydwie diody:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([0, 0])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Wydanie poniższego polecenia spowoduje, iż mikrokontroler zapali podłączoną do niego diodę numer 1 na czas 100 ms, zaś diodę numer 2 na 200 ms. Jednocześnie, w momencie włączenia jak i wyłączenia diody, sygnał z mikrokontrolera zostanie wysłany na 5-stykowe wejście AUX mikrokontrolera:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([100, 200])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Jeśli chcemy zapalić tylko diodę numer dwa, np. na czas 500 ms w programie podajemy następującą instrukcję:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([0, 500])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Jeśli chcemy zakończyć komunikację z mikrokontrolerem piszemy:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.close()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kod biblioteki do komunikacji z mikrokontrolerem:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: cp1250 -*-&lt;br /&gt;
import serial&lt;br /&gt;
import logging&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def to_hex_word(a):&lt;br /&gt;
    '''encodes a decimal number hexadecimally on two bytes'''&lt;br /&gt;
    return chr(a%256) + chr(a/256)&lt;br /&gt;
&lt;br /&gt;
class SerialPort(object):&lt;br /&gt;
    def __init__(self, port_name):&lt;br /&gt;
        import serial&lt;br /&gt;
        try:&lt;br /&gt;
            self.port = serial.Serial(&lt;br /&gt;
                port=port_name,&lt;br /&gt;
                baudrate=9600,&lt;br /&gt;
                bytesize=serial.EIGHTBITS,&lt;br /&gt;
                parity=serial.PARITY_NONE,&lt;br /&gt;
                stopbits=serial.STOPBITS_ONE,&lt;br /&gt;
                xonxoff=False&lt;br /&gt;
                )&lt;br /&gt;
        except serial.SerialException, e:&lt;br /&gt;
            print &amp;quot;Nieprawidłowa nazwa portu lub port zajęty.&amp;quot;&lt;br /&gt;
            raise e&lt;br /&gt;
        self.close()&lt;br /&gt;
        &lt;br /&gt;
    def open(self):&lt;br /&gt;
        self.port.open()&lt;br /&gt;
&lt;br /&gt;
    def close(self):&lt;br /&gt;
        self.port.close()&lt;br /&gt;
&lt;br /&gt;
    def send(self, value):&lt;br /&gt;
        self.port.write(value)&lt;br /&gt;
                           &lt;br /&gt;
    def blinkSSVEP(self,d, p1, p2):&lt;br /&gt;
        '''&lt;br /&gt;
        d = list of frequencies;&lt;br /&gt;
        p1:p2 = ratio LED_on_time/LED_off_time&lt;br /&gt;
        if you want i-th LED to be OFF all the time send  d[i] = 0&lt;br /&gt;
        if you want i-th LED to be ON all the time send  d[i] = -1&lt;br /&gt;
        in these two cases p1 and p2 do not matter&lt;br /&gt;
        '''&lt;br /&gt;
        clock  = 62500&lt;br /&gt;
        factor = float(p1) / float(p1 + p2)&lt;br /&gt;
    &lt;br /&gt;
        str = chr(3) # 'SSVEP_RUN'&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(d)):&lt;br /&gt;
            # i-th LED OFF&lt;br /&gt;
            if d[i] == 0:                       &lt;br /&gt;
                str += to_hex_word(0) + to_hex_word(255) &lt;br /&gt;
            # i-th LED ON&lt;br /&gt;
            elif d[i] == -1:&lt;br /&gt;
                str += to_hex_word(255) + to_hex_word(0)&lt;br /&gt;
                #str = 'S'&lt;br /&gt;
                # i-th LED blinks d[i] times per second&lt;br /&gt;
                # p1:p2 = on_time:off_time in one blink&lt;br /&gt;
            else:&lt;br /&gt;
                period = clock/d[i]&lt;br /&gt;
                bright = int((clock/d[i]) * factor)&lt;br /&gt;
                dark = period - bright&lt;br /&gt;
                str += to_hex_word(bright) + to_hex_word(dark)&lt;br /&gt;
&lt;br /&gt;
        self.send(str)&lt;br /&gt;
&lt;br /&gt;
    def blinkP300(self,d):&lt;br /&gt;
        clock  = 62500&lt;br /&gt;
        str = chr(4) # 'P300_RUN'&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(d)):&lt;br /&gt;
            period = int(clock*d[i]/1000.0)&lt;br /&gt;
            str += to_hex_word(period)&lt;br /&gt;
            print(period)&lt;br /&gt;
&lt;br /&gt;
        self.send(str)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zestaw eksperymentalny===&lt;br /&gt;
Zestaw składa się ze:&lt;br /&gt;
* wzmacniacza,&lt;br /&gt;
* stymulatora &amp;amp;mdash; układ zapalający i gaszący diodę w kontrolowany sposób,  &lt;br /&gt;
* izolowanego galwanicznie układu generującego impulsy odpowiadające gaszeniu i zapalaniu diody,  o wartościach dopasowanych do akceptowalnych przez wejścia AUX wzmacniacza,&lt;br /&gt;
* komputera: w tym eksperymencie komputer będzie służył do zaprogramowania stymulatora i do rejestracji sygnałów.&lt;br /&gt;
&lt;br /&gt;
===Wersja 1: obserwacja błyskającej diody  ===&lt;br /&gt;
&amp;lt;!--Proszę zapoznać się ze standardami rejestracji wzrokowych potencjałów wywołanych [http://www.gcu.ac.uk/media/gcalwebv2/theuniversity/academicschools/sls/psytimetables/SLS%20-%20VEP_Standard_2010.pdf] --&amp;gt;&lt;br /&gt;
Proszę zapoznać się z typowym wyglądem załamków w przypadku potencjałów wzrokowych, jaki jest przedstawiony na [https://static-content.springer.com/image/art%3A10.1007%2Fs10633-009-9195-4/MediaObjects/10633_2009_9195_Fig4_HTML.gif tym rysunku] (cały artykuł jest dostępny [http://link.springer.com/article/10.1007%2Fs10633-009-9195-4 tu]).&lt;br /&gt;
&amp;lt;!--[[Plik:Fig 4 VEP.jpg|thumb|320px|right|&amp;lt;figure id=&amp;quot;fig:zalamki_VEP&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
&amp;lt;xr id=&amp;quot;fig:zalamki_VEP&amp;quot;&amp;gt;Rys. %i.&amp;lt;/xr&amp;gt; Schemat załamków rozpoznawanych we wzrokowych potencjach wywołanych (z pracy: J. V. Odom i in. &amp;amp;bdquo;ISCEV standard for clinical visual evoked potentials&lt;br /&gt;
(2009 update)&amp;amp;rdquo;, Doc Ophthalmol (2010), 120:111–119).]]&lt;br /&gt;
--&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
* Paradygmat: z odległości około 40 cm badany obserwuje błyski diody. Błyski powtarzają się co 1&amp;amp;plusmn;0,1 sekundy. Każdy błysk trwa 20 ms. Rejestrujemy 2 serie po 100 błysków. Częstość próbkowania 512 Hz.&lt;br /&gt;
** W pierwszej serii błyskamy tylko jedną diodą.&lt;br /&gt;
** W drugiej serii błyskamy dwiema diodami. &lt;br /&gt;
Pomiędzy seriami badany odpoczywa około 2 min. Diody powinny być ustawione na jednakową jasność błysków.&lt;br /&gt;
&lt;br /&gt;
* Pomiar&lt;br /&gt;
**Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%. [[Plik:Glowka10-20 ERPy.svg|thumb|600px|right]]&lt;br /&gt;
** Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
** Montujemy także elektrodę FCz (na linii centralnej pomiędzy Fz a Cz), będziemy jej używać w montażu i w czasie analizy jako referencji.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +400 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy wycięte sygnały.&lt;br /&gt;
# Rysujemy średni potencjał we wszystkich kanałach.&lt;br /&gt;
# Identyfikujemy załamki N2 i P2. Mierzymy amplitudę P2 jako różnicę między ekstremalną wartością załamka P2 a ekstremalną wartością załamka N2. &lt;br /&gt;
&lt;br /&gt;
[[Plik:ZalamkiN2_P2.png‎|thumb|600px|right|  Uśredniony potencjał wywołany dla serii 1 i 2 na kanale T5 z zaznaczonymi załamkami N2 i P2. Na osi poziomej czas [s] natomiast na pionowej amplituda [μV].]]&lt;br /&gt;
Pomiar wykonujemy dla obu serii błysków.&lt;br /&gt;
&lt;br /&gt;
Pytanie: Czy intensywność bodźca wpływa na amplitudę potencjału P2?&lt;br /&gt;
Jak stwierdzić czy amplitudy załamków P2 istotnie różnią się pomiędzy seriami?&lt;br /&gt;
&lt;br /&gt;
Musimy przeprowadzić test statystyczny. Możemy skonstruować go np. tak:&lt;br /&gt;
Mamy dwa warunki I i II. Jako statystykę przyjmiemy różnicę pomiędzy amplitudą załamka zmierzoną w serii z dwoma diodami (P2&amp;lt;sub&amp;gt;II&amp;lt;/sub&amp;gt;) a amplitudą zmierzoną w serii z jedną diodą (P2&amp;lt;sub&amp;gt;I&amp;lt;/sub&amp;gt;):&lt;br /&gt;
: ''S'' = P2&amp;lt;sub&amp;gt;II&amp;lt;/sub&amp;gt; &amp;amp;minus; P2&amp;lt;sub&amp;gt;I&amp;lt;/sub&amp;gt;&lt;br /&gt;
Postawmy hipotezę zerową, że nie ma różnicy w amplitudzie pomiędzy warunkiem II a I oraz hipotezę alternatywną, że różnica taka występuje.&lt;br /&gt;
: H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;: ''S'' = 0&lt;br /&gt;
: H&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;: ''S'' &amp;amp;ne; 0&lt;br /&gt;
Zgodnie z H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; dla wartości ''S'' nie ma różnicy czy realizacja została zarejestrowana w warunkach I czy II, zatem można losowo poprzypisywać numery warunków do realizacji i w ten sposób uzyskać rozkład statystyki ''S'' pod warunkiem prawdziwości H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;, czyli obliczyć średnie potencjały dla &amp;amp;bdquo;pomieszanych&amp;amp;rdquo; tagów, wyliczyć średnie potencjały dla sztucznie wygenerowaych grup, i wyliczyć różnicę amplitud dla tych średnich, czyli wartość statystyki dla hipotezy H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Zaimplementuj test permutacyjny zgodny z powyższą koncepcją.&lt;br /&gt;
&lt;br /&gt;
===Wersja 2: obserwacja habituacji / uśrednianie w blokach ===&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
# Paradygmat: &lt;br /&gt;
#* z odległości około 40 cm badany obserwuje błyski diody. &lt;br /&gt;
#* Błyski powtarzają się co 0,5 sekundy. &lt;br /&gt;
#* Rejestrujemy 60 serii po 15 błysków.  &lt;br /&gt;
#* Pomiędzy seriami badany odpoczywa około 10 sekund.&lt;br /&gt;
# Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%.&lt;br /&gt;
#* Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
#* Montujemy także elektrodę FCz (na linii centralnej pomiędzy Fz a Cz), będziemy jej używać w montażu i w czasie analizy jako referencji.&lt;br /&gt;
#* Częstość próbkowania 512 Hz.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +600 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy wycięte sygnały o tym samym numerze wewnątrz serii.&lt;br /&gt;
# Rysujemy serie 15 uśrednionych potencjałów dla tego kanału, który wykazywał najsilniejszy potencjał w pierwszej wersji eksperymentu.&lt;br /&gt;
&lt;br /&gt;
==Zadanie 3: rejestracja i analiza potencjału P3 ==&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
# Paradygmat: &lt;br /&gt;
#* z odległości około 40 cm badany obserwuje błyski diody. &lt;br /&gt;
#* Błyski diody nr 1 powtarzają się co 1&amp;amp;plusmn;0,1 sekundy. &lt;br /&gt;
#* W losowych realizacjach zapalana jest także dioda nr 2. &lt;br /&gt;
#* Proporcja pomiędzy ilością błysków pojedynczych i podwójnych powinna wynosić 10:2, przy czym błyski podwójne muszą być odseparowane co najmniej jednym błyskiem pojedynczym. &lt;br /&gt;
#* Czas zapalenia diod, tak jak w poprzednich eksperymentach, wynosi 20 ms. &lt;br /&gt;
#* Zadaniem badanego jest liczenie liczby błysków podwójnych.&lt;br /&gt;
#* Wykonujemy tyle realizacji aby zarejestrować 50 powtórzeń podwójnych błysków. &lt;br /&gt;
# Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%.&lt;br /&gt;
#* Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
#* Montujemy także elektrody M1 i M2, będziemy ich używać w montażu i w czasie analizy jako referencji typu połączone uszy.&lt;br /&gt;
#* Częstość próbkowania 512 Hz.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +600 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy osobno realizacje błysków pojedynczych i błysków podwójnych.&lt;br /&gt;
# Nakładamy na siebie na rysunkach oba typy średnich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ćwiczenie dodatkowe: P300 BCI==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wykorzystujemy elektrody z systemu 10-10 umieszczone nad korą wzrokową: P07, O1, O2, PO8, PO3, PO4, Pz, Cz.&lt;br /&gt;
&lt;br /&gt;
Uruchamiamy &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
obci_gui --presets eeg_workshop&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i z guzika &amp;amp;bdquo;select amplifier&amp;amp;rdquo; wybieramy właściwy wzmacniacz.&lt;br /&gt;
&lt;br /&gt;
Do kontroli jakości sygnału możemy uruchomić Svaroga.&lt;br /&gt;
&lt;br /&gt;
Dane z kalibracji zapisują się w pliku test1 w katalogu domowym użytkownika, z labiryntu w pliku test2.&lt;br /&gt;
&lt;br /&gt;
Po zakończeniu kalibracji pojawia się napis &amp;amp;bdquo;Trwają obliczenia&amp;amp;rdquo; lub podobny. Odczekujemy kilka minut, aż skończy się peer &amp;amp;bdquo;Calibration&amp;amp;rdquo; (widoczny w obci_gui) i zamykamy okienko klawiszami Alt-F4 lub zatrzymując scenariusz guzikiem &amp;amp;bdquo;Stop&amp;amp;rdquo;. W katalogu domowym pojawi się plik z wynikami kalibracji, co pozwala na uruchomienie scenariusza &amp;amp;bdquo;labirynt&amp;amp;rdquo;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Po zebraniu danych, przed wczytaniem ich do Svaroga należy w tym samym katalogu uruchomić skrypt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.obci_signal_processing.tags import tags_file_writer&lt;br /&gt;
from obci.analysis.obci_signal_processing.read_manager import ReadManager&lt;br /&gt;
&lt;br /&gt;
def main(): &lt;br /&gt;
	file_name = 'test1'&lt;br /&gt;
	&lt;br /&gt;
	mgr = ReadManager(&lt;br /&gt;
		file_name + '.obci.xml',&lt;br /&gt;
		file_name + '.obci.raw',&lt;br /&gt;
		file_name + '.obci.tag')&lt;br /&gt;
	&lt;br /&gt;
	tags = mgr.get_tags()&lt;br /&gt;
	for i in xrange(0, len(tags)):&lt;br /&gt;
		if tags[i]['desc']['index'] == tags[i]['desc']['target']:&lt;br /&gt;
			tags[i]['name'] = 'blink_target'&lt;br /&gt;
		else:&lt;br /&gt;
			tags[i]['name'] = 'blink'&lt;br /&gt;
			&lt;br /&gt;
	tags_writer = tags_file_writer.TagsFileWriter(file_name + '.obci.tag')&lt;br /&gt;
	for tag in tags:&lt;br /&gt;
		tags_writer.tag_received(tag)		&lt;br /&gt;
	tags_writer.finish_saving(0)	&lt;br /&gt;
 &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_EEG/Potencja%C5%82y_wywo%C5%82ane&amp;diff=7895</id>
		<title>Pracownia EEG/Potencjały wywołane</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Pracownia_EEG/Potencja%C5%82y_wywo%C5%82ane&amp;diff=7895"/>
		<updated>2018-10-25T11:51:55Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Synchronizacja występowania bodźców z sygnałem EEG */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Pracownia EEG|Pracownia EEG]] / Potencjały wywołane&lt;br /&gt;
&lt;br /&gt;
=Wstęp=&lt;br /&gt;
==Potencjały wywołane==&lt;br /&gt;
=== Wstęp ===&lt;br /&gt;
Potencjały wywołane EEG (ang. ''evoked potentials'', EP) są śladami odpowiedzi mózgu na bodźce. W przypadku MEG poprawnie mówi się o polach wywołanych (ang. ''evoked fields'', EF).&lt;br /&gt;
Zwykle reakcja ta jest mała (wyjątek stanowią [[Elektroencefalografia/Metody_analizy_sygnałów_EEG_-_analiza_w_dziedzinie_czasu |kompleksy K]]) i w zapisie pojedynczej realizacji reakcji na bodziec najczęściej niewidoczna wśród czynności pochodzącej od wielu innych procesów zachodzących w tym samym czasie w mózgu. &lt;br /&gt;
Ich wyodrębnienie z tak zwanego tła EEG/MEG, czyli manifestacji elektrycznej innych, trwających w tym samym czasie w mózgu procesów (aktywny prąd niezależny), wymaga w dniu dzisiejszym zapisu odpowiedzi na szereg powtórzeń tego samego bodźca (&amp;lt;xr id=&amp;quot;fig:EP&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Pierwsze potencjały wywołane pokazał pod koniec lat 40-tych Dawson (Dawson 1947) wykonując superpozycję pojedynczych realizacji na kliszy fotograficznej.&lt;br /&gt;
Z czasem skomplikowane urządzenia analogowe zastąpione zostały przez cyfrowe uśrednianie kolejnych fragmentów EEG, zsynchronizowanych według momentu wystąpienia bodźca, łatwo realizowane za pomocą komputera.&lt;br /&gt;
&lt;br /&gt;
[[Grafika:EP.png|thumb|640px|center|&amp;lt;figure id=&amp;quot;fig:EP&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
Uśrednianie potencjałów wywołanych. a) ciągły zapis EEG z wyróżnionymi momentami wystąpienia bodźca (w tym przypadku słuchowego) b) kilkadziesiąt kolejnych odcinków, wyciętych jako sekunda EEG od momentu wystąpienia kolejnych bodźców, ustawione jeden pod drugim c) uśredniony potencjał wywołany &amp;amp;mdash; widać m. in. załamek P300 ok. 300 milisekund po bodźcu]]&lt;br /&gt;
&lt;br /&gt;
Techniki te opierają się na założeniu, że zawarta w EEG odpowiedź mózgu na każdy z kolejnych bodźców jest niezmienna, a EEG odzwierciedlające pozostałe procesy traktowane jest jak nieskorelowany z nią proces stochastyczny. Zależnie od rodzaju potencjałów wywołanych, założenia te są mniej lub bardziej nieuzasadnione; podważa je choćby powszechnie znany efekt habituacji, polegający na osłabieniu późnych potencjałów wywołanych kolejnymi powtórzeniami bodźca.&lt;br /&gt;
&lt;br /&gt;
Istota potencjałów wywołanych jest przedmiotem otwartej dyskusji i dziesiątków prac, dotykających od lat podstawowych w tej dziedzinie pytań: czym jest potencjał wywołany, który widzimy w uśrednionym przebiegu? Czy naprawdę wynika z deterministycznie powtarzanej, jednakowej odpowiedzi pojawiającej się po każdym powtórzeniu bodźca niezależnie od &amp;amp;bdquo;tła&amp;amp;rdquo;, czy może wynika z reorganizacji faz tego właśnie &amp;amp;bdquo;tła&amp;amp;rdquo; EEG, czy może kombinacji tych dwóch efektów? Jest to wspaniałe pole dla zastosowań zaawansowanych metod modelowania i analizy sygnałów. W ostatnich latach powstają dziesiątki prac na ten temat, a od czasu do czasu również krytyczne artykuły wykazujące, że dotychczasowe odkrycia są raczej artefaktami stosowanych metod a nie wynikają z własności analizowanych danych (Yeung et al., 2004). Jak widać jest tu wciąż bardzo wiele do zrobienia, gdyż zrozumienie tego mechanizmu stoi na drodze do &amp;amp;bdquo;świętego Graala&amp;amp;rdquo;, którym w tej dziedzinie jest wyodrębnienie pojedynczych potencjałów wywołanych.&lt;br /&gt;
&lt;br /&gt;
Niezależnie od tego, w neurofizjologii klinicznej nazwą potencjał wywołany określa się krzywą widoczną po uśrednieniu odpowiedzi na kilkanaście do kilku tysięcy bodźców (Szelenberger 2000). Gromadzona od dziesięcioleci wiedza o behawioralnych i klinicznych korelatach potencjałów wywołanych opiera się na rozpoznawaniu w przebiegach uśrednionych tak zwanych załamków, czyli przejściowych wzrostów lub spadków potencjału (na przykład na &amp;lt;xr id=&amp;quot;fig:EP&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt; widać załamek P300). Nazwy załamków składają się zwykle z litery &amp;amp;bdquo;P&amp;amp;rdquo; (od ang. ''positive''), jeśli wychylenie jest dodatnie, lub &amp;amp;bdquo;N&amp;amp;rdquo; (od ang. ''negative''), jeśli wychylenie jest ujemne, oraz liczby. Uwaga: &lt;br /&gt;
* Nie ma niestety jednej ustalonej konwencji prezentacji potencjałów koniecznie trzeba więc zwracać uwagę na orientację wykresu, a wykonując wykres samemu - zamieszczać informację o orientacji kierunku dodatniego,gdyż kierunek dodatni może być wykresie skierowany do góry lub do dołu. &lt;br /&gt;
* Liczba następująca po N lub P określa przybliżoną liczbę milisekund od wystąpienia bodźca, czyli tak zwaną latencję. Nie można jednak ścisłego związku między tą liczbą a liczbą milisekund np. potencjał P300 w zależności od szczegółów paradygmatu doświadczalnego może wystąpić znacznie później. np. w eksperymentach językowych zdarza się że P300 występuje później niż N400 :-).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xr id=&amp;quot;fig:zalamki&amp;quot;&amp;gt;Rys. %i&amp;lt;/xr&amp;gt; przedstawia schematycznie najważniejsze załamki rozpoznawane w potencjałach słuchowych, czyli wywoływanych bodźcem dźwiękowym. Dla potencjałów wzrokowych i somatosensorycznych istnieją podobne klasyfikacje.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Grafika:Zalamki.png|thumb|320px|right|&amp;lt;figure id=&amp;quot;fig:zalamki&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
Orientacyjny schemat załamków rozpoznawanych w słuchowych potencjach wywołanych, na podstawie (Szelenberger 2000). Skala czasu logarytmiczna. Najszybsze (do 12 ms) składowe egzogenne to potencjały pniowe (BAEP), oznaczane jako fale I-VII. Litery &amp;amp;bdquo;P&amp;amp;rdquo; i &amp;amp;bdquo;N&amp;amp;rdquo; oznaczają dodatnie i ujemne wychylenia związane z dalszymi załamkami]]&lt;br /&gt;
&lt;br /&gt;
Najszybsze (czyli o najmniejszej latencji) składowe to potencjały egzogenne, odzwierciedlające wstępne fazy przekazu informacji. W potencjałach słuchowych są to potencjały pnia (ang. ''brainstem auditory evoked potentials'', BAEP), składające się z siedmiu fal występujących pomiędzy 1 a 12 ms od bodźca. Są one generowane np. w nerwie słuchowym czy pniu mózgu, i wykorzystywane w klinicznej diagnostyce integralności dróg słuchowych. Podobnie jak inne wczesne potencjały o latencjach poniżej 100 ms, są praktycznie niezależne od stanu uwagi.&lt;br /&gt;
&lt;br /&gt;
Po potencjałach o średniej latencji (między 12 a 50 ms) zaczynają się późne potencjały słuchowe, odzwierciedlające bardziej złożone reakcje na bodziec. Na przykład amplituda załamka N100 wzrasta w stanie skupienia uwagi czy pobudzenia emocjonalnego. Około 200 milisekund po bodźcu pojawia się załamek odzwierciedlający modną ostatnio ''falę niezgodności'' (ang. ''mismatch negativity''). Jest on wyrazem nieświadomej i automatycznej reakcji na zmianę bodźca &amp;amp;mdash; na przykład na pojawiające się stosunkowo rzadko dźwięki o innej częstości w serii dźwięków o jednakowej wysokości. Wreszcie pierwszy i najpopularniejszy całkowicie endogenny załamek to P300, pojawiający się po rozpoznaniu bodźca oczekiwanego, na którym skupiamy uwagę: na przykład, jeśli w serii pojawiających się losowo liter mamy zliczać wystąpienia jednej z nich, to na średniej odpowiedzi na pojawienie się tej litery pojawi się załamek P300.&lt;br /&gt;
&lt;br /&gt;
=== Uśrednianie w dziedzinie czasu ===&lt;br /&gt;
Jak już było wspomniane powyżej podstawową techniką stosowaną do analizy potencjałów wywołanych jest uśrednianie wielu realizacji odpowiedzi na bodziec wyrównanych względem jakiegoś charakterystycznego zdarzenia, np. momentu podania bodźca albo momentu behawioralnej reakcji na bodziec (np. wciśnięcie przycisku). Podejście to bazuje na trzech założeniach:&lt;br /&gt;
* Reakcja jest czasowo związana z bodźcem. Tzn. w kolejnych realizacjach występuje ona zawsze z tym samym opóźnieniem.&lt;br /&gt;
* Reakcja na bodziec skutkuje zawsze pojawieniem się w sygnale składowej o stałym kształcie (mówimy o stałej morfologii).&lt;br /&gt;
* Spontaniczna czynność EEG &amp;amp;mdash; ta która nie dotyczy przetwarzania interesującego nas bodźca &amp;amp;mdash; jest niezależnym, stacjonarnym szumem o średniej zero.&lt;br /&gt;
&lt;br /&gt;
Zgodnie z powyższymi założeniami mierzony w ''i''-tej realizacji sygnał można wyrazić jako:&lt;br /&gt;
: &amp;lt;math&amp;gt;x_i(t) = s(t) + n_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
Uśrednianie po ''N'' realizacjach daje:&lt;br /&gt;
: &amp;lt;math&amp;gt;\bar x (t) = \frac{1}{N} \sum_{i=1}^N x_i(t) = \frac{1}{N} \left(N s(t) + \sum_{i=1}^N n_i(t) \right) &amp;lt;/math&amp;gt;&lt;br /&gt;
Wartość oczekiwana średniego sygnału wynosi:&lt;br /&gt;
: &amp;lt;math&amp;gt;\mathrm{E}\left[ \bar x(t) \right] = s(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
gdyż dla szumu o średniej zero mamy:&lt;br /&gt;
: &amp;lt;math&amp;gt;\mathrm{E}\left[\frac{1}{N} \sum_{i=1}^N n_i(t)\right] = 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
Wariancja &amp;lt;math&amp;gt;\bar x(t)&amp;lt;/math&amp;gt; wynosi:&lt;br /&gt;
: &amp;lt;math&amp;gt;\sigma^2_{\bar x(t)} = \mathrm{E} \left[  \left( \frac{1}{N} \sum_{i=1}^N n_i(t)\right)^2 \right] \approx \frac{1}{N} \sigma^2_{n(t)}&amp;lt;/math&amp;gt;&lt;br /&gt;
gdyż &amp;lt;math&amp;gt;s(t)&amp;lt;/math&amp;gt; jest deterministyczne. &lt;br /&gt;
&lt;br /&gt;
Dla potencjałów pojawiających się w pierwszych kilkudziesięciu milisekundach po bodźcu model ten można uznać za poprawny, gdyż wykazują one zależność głównie od parametrów fizycznych bodźca. Dla późniejszych składowych staje się on coraz bardziej wątpliwy ze względu na występujące korelacje ze stanem (np. uwagi) badanego.&lt;br /&gt;
&lt;br /&gt;
Dla późniejszych składowych można by postulować bardziej ogólną wersję modelu potencjału wywołanego:&lt;br /&gt;
: &amp;lt;math&amp;gt;x_i(t) = s_i(t) + n_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
Ten model uwidacznia, że do opisu potencjału wywołanego potrzebna jest nie tylko średnia, ale i wyższe momenty rozkładu (np. drugi moment centralny czyli wariancja).&lt;br /&gt;
&lt;br /&gt;
====Wariancja w przypadku szumu skorelowanego ====&lt;br /&gt;
W poprzednim paragrafie pokazaliśmy, że w przypadku niezależnego szumu wariancja uśrednionego sygnału (w danej chwili czasu) maleje jak  &amp;lt;math&amp;gt;\frac{1}{N}&amp;lt;/math&amp;gt;. Jednak w przypadku gdy kolejne próbki szumu są skorelowane (np. występuje silna aktywność rytmiczna alfa) sytuacja się komplikuje. Intuicyjnie łatwo możemy to sobie wyobrazić w granicznym przypadku. Załóżmy, że tło dla  potencjałów o stałej morfologii   stanowi sinusoida. Jeśli będziemy podawać bodźce w odstępach będących wielokrotnością okresu tej sinusoidy to w uśrednianych fragmentach sygnału owa sinusoida jest tak samo powtarzalna jak badany potencjał i uśrednianie nie prowadzi do poprawy stosunku amplitudy sygnału do amplitudy tła. &lt;br /&gt;
&lt;br /&gt;
Stopień zależności pomiędzy próbkami można zmierzyć przy pomocy funkcji autokorelacji. &lt;br /&gt;
Jeśli funkcję autokorelacji przybliżymy przez:&lt;br /&gt;
: &amp;lt;math&amp;gt;R_{xx}(\tau) = \sigma^2 \exp(-\beta |\tau|) \cos(2 \pi f_0 \tau)&amp;lt;/math&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;\sigma^2&amp;lt;/math&amp;gt; jest wariancją szumu, &amp;lt;math&amp;gt;f_0&amp;lt;/math&amp;gt; jest średnią częstością aktywności rytmicznej, &amp;lt;math&amp;gt;\beta/ \pi&amp;lt;/math&amp;gt; jest szerokością pasma tej czynności, zaś &amp;lt;math&amp;gt;\tau&amp;lt;/math&amp;gt; opóźnieniem, to wariancję potencjału wywołanego można wyrazić jako&amp;lt;!-- \cite{Spekreijse_1976}--&amp;gt;:&lt;br /&gt;
: &amp;lt;math&amp;gt;\sigma^2_{\bar x(t)} = \frac{\sigma^2}{N} \left[ \frac{1-\exp(-2 \beta T)}{1 - 2 \exp(- \beta T) \cos(2 \pi f_0 T) +\exp(-2 \beta T)} \right]&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; jest odstępem między bodźcami. &lt;br /&gt;
Widać stąd, że obecność czynności rytmicznej w tle wpływa na stosunek sygnału do szumu. Z powyższego równania widać, że stosunek wariancji dąży do &amp;lt;math&amp;gt;\frac{\sigma^2}{N}&amp;lt;/math&amp;gt; gdy &amp;lt;math&amp;gt;\beta T&amp;lt;/math&amp;gt; staje się duże.  &lt;br /&gt;
&lt;br /&gt;
Periodyczna stymulacja może ponadto prowadzić do wzbudzenia czynności rytmicznej o częstości równej częstości pobudzania bądź jej harmonicznej.&lt;br /&gt;
&lt;br /&gt;
===Wariancja latencji===&lt;br /&gt;
&lt;br /&gt;
Jedną z form zmienności potencjału wywołanego w pojedynczych realizacjach jest wariancja latencji. &lt;br /&gt;
[[Grafika:Wariancja_latencji.png|thumb|500px|right|&lt;br /&gt;
Czerwona linia: Uśrednianie 100 potencjałów wywołanych o latncjach z rozkładu normalnego N(300,30 ), Niebieskie linie: przykładowe pojedyncze realizacje wzięte do średniej]]&amp;lt;!--# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show ,subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
 &lt;br /&gt;
def fun(t,lat=100):&lt;br /&gt;
    return np.exp(-(t-lat)**2/(2*30**2))&lt;br /&gt;
Fs = 1&lt;br /&gt;
N = 100&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
f = np.zeros((N,700))&lt;br /&gt;
f_sr = np.zeros(t.shape)&lt;br /&gt;
for i in range(N):&lt;br /&gt;
    f[i,:] = fun(t,lat = 300 + 30* np.random.randn())&lt;br /&gt;
for i in range(3):&lt;br /&gt;
    plot(t,f[i,:], 'b')&lt;br /&gt;
plot(t,f.mean(0),'r')&lt;br /&gt;
show()--&amp;gt;&lt;br /&gt;
Zmienność latencji prowadzi do:&lt;br /&gt;
* zmniejszenia amplitudy &amp;lt;math&amp;gt;\bar x&amp;lt;/math&amp;gt;&lt;br /&gt;
* wzrostu rozciągłości czasowej załamka&lt;br /&gt;
&lt;br /&gt;
O tych konsekwencjach zmienności latencji należy w szczególności pamiętać porównując średnie potencjały uzyskane w różnych warunkach eksperymentalnych. Gdy zauważymy, że średnie potencjały różnią się amplitudą należy rozważyć możliwość, że w istocie warunki eksperymentalne wpływają na różnice w wariancji latencji. &lt;br /&gt;
&lt;br /&gt;
Naturalne jest, że zmienność latencji jest bardziej widoczna w przypadku załamków trwających krótko niż w przypadku załamków trwających długo. Wariancja latencji rożnie wraz z jej wartością, stąd wśród późnych składowych potencjałów wywołanych nie obserwuje się komponentów krótkotrwałych.&lt;br /&gt;
====Uśrednianie metodą Woody'ego ====&lt;br /&gt;
&lt;br /&gt;
Model potencjału ze zmienną latencją i sposób na jego efektywniejsze uśrednianie zaproponował Woody (1967). Model ten zakłada, że w każdej realizacji występuje komponent addytywny &amp;lt;math&amp;gt;s_i(t)\;&amp;lt;/math&amp;gt;, który co do kształtu jest stały, a pomiędzy realizacjami różni się tylko latencją:&lt;br /&gt;
: &amp;lt;math&amp;gt; s_i(t) = s(t +\Delta t_i)\;&amp;lt;/math&amp;gt;&lt;br /&gt;
Woody zaproponował aby &amp;lt;math&amp;gt;\Delta t_i\;&amp;lt;/math&amp;gt; szacować na podstawie maksimum funkcji korelacji wzajemnej pomiędzy ''i''-tą realizacją a wzorcem. W pierwszym kroku wzorcem jest średni potencjał uzyskany przez proste uśrednienie realizacji.  Następnie w sposób iteracyjny dokonuje się:&lt;br /&gt;
* poprawek w wyrównaniu poszczególnych realizacji,&lt;br /&gt;
* obliczenia nowego wzorca poprzez uśrednienie realizacji po korekcie wyrównania,&lt;br /&gt;
* obliczenia nowych poprawek do wyrównania realizacji.&lt;br /&gt;
&lt;br /&gt;
===Habituacja ===&lt;br /&gt;
Zmienność w odpowiedziach na kolejno występujące po sobie bodźce można podzielić na komponent stochastyczny i deterministyczny. Komponent deterministyczny odzwierciedla zmianę czułości  układu nerwowego  na kolejne bodźce. Nowy bodziec często wywołuje reakcje pobudzenia widoczną w wielu parametrach takich jak przewodnictwo skóry, rytm serca i reaktywność kory mózgowej. Powszechnie obserwowanym zjawiskiem jest spadek reaktywności na powtarzające się bodźce zwany habituacją. Niekiedy obserwuje się także zjawisko przeciwne &amp;amp;mdash; wzrost reaktywności na bodziec &amp;amp;mdash; zwane sensytyzacją. &lt;br /&gt;
&lt;br /&gt;
Klasycznym sposobem na badanie tych zjawisk w potencjałach wywołanych jest uśrednianie w podzbiorach lub  uśrednianie blokowe. Wymaga ono  zmiany paradygmatu rejestracji danych. Załóżmy, że interesującym nas bodźcem jest błysk światła. Chcemy zaobserwować ewentualne zmiany amplitudy i latencji w ciągu 100 potencjałów będących reakcją na błysk powtarzający się co 500 ms.&lt;br /&gt;
====Uśrednianie w podzbiorach ====&lt;br /&gt;
W metodzie tej musimy założyć, że proces habituacji jest powolny, tzn. zmiany pomiędzy kolejnymi reakcjami są bardzo małe. W takim przypadku możemy podzielić długą serię bodźców na ciąg pod-serii i uśrednienie przeprowadzić dla każdej pod-serii osobno.&lt;br /&gt;
[[Plik:Usrednianie_podzbiory.svg‎|640px|thumb|center|Ilustracja uśredniania w podzbiorach]]&lt;br /&gt;
&lt;br /&gt;
====Uśrednianie blokowe====&lt;br /&gt;
W tym celu eksperyment wykonujemy w wielu seriach. Jedna seria składa się ze 100 błysków powtarzanych co 500 ms.  Po serii następuje przerwa trwająca np. 5 s (długość przerwy wyraża nasze oszacowanie czasu potrzebnego na zanik habituacji). Po przerwie seria jest powtarzana. Powtórzeń serii wykonujemy ''N''.&lt;br /&gt;
Następnie uśredniamy fragmenty sygnałów odpowiadające sobie w kolejnych seriach. &lt;br /&gt;
&lt;br /&gt;
W tym paradygmacie zakładamy, że każda seria rejestrowana jest w tych samych warunkach. Zaniedbujemy efekty związane ze zmęczeniem i zmianami w np. stopniu koncentracji badanego.&lt;br /&gt;
[[Plik:Usrednianie blokowe.svg|Usrednianie blokowe.svg|640px|thumb|center|Ilustracja uśredniania w blokach]]&lt;br /&gt;
&lt;br /&gt;
===Załamki w krzywej potencjału wywołanego vs ukryte komponenty===&lt;br /&gt;
Komponenta potencjału wywołanego to bardzo ważne ale jednocześnie źle określone pojęcie. Krzywa otrzymana w wyniku uśredniania potencjałów wywołanych przedstawia serię załamków dodatnich i ujemnych, ale trzeba być świadomym, że ten przebieg napięcia rejestrowany przez elektrody przedstawia tak naprawdę sumę potencjałów pochodzących od wielu dość niezależnie działających źródeł w mózgu. Przyczynek pochodzący od jednego funkcjonalnego źródła będziemy określać jako komponentę. &lt;br /&gt;
&lt;br /&gt;
Komentarza wymaga też pojęcie źródła funkcjonalnego. Czynność elektryczną synchronicznie działających neuronów piramidalnych w określonym fragmencie kory mózgowej z pewnej odległości można przybliżyć potencjałem dipola prądowego. Taki aktywny fragment kory stanowi źródło dające przyczynek do mierzonego na powierzchni głowy potencjału. W najprostszej sytuacji taki przyczynek może być obserwowany jako komponenta. Mózg jest jednak obiektem niezwykle złożonym i gęsto połączonym. Wiele obszarów korowych może być funkcjonalnie połączonych i aktywowanych synchronicznie w celu realizacji określonego zadania &amp;amp;mdash; o takim funkcjonalnym zespole też możemy myśleć jako o pojedynczym źródle, choć może ono mieć złożoną strukturę przestrzenną. Często zatem myślimy o komponentach ukrytych potencjału wywołanego jako o aktywności takich funkcjonalnych zespołów. &lt;br /&gt;
&lt;br /&gt;
Po tym wstępie widać już chyba, że do zrozumienia co dzieje się w czasie reakcji na bodziec, którą obserwujemy w potencjale wywołanym, bardziej pożądane byłoby badanie komponent ukrytych niż poszczególnych załamków krzywej potencjału wywołanego, która stanowi ważoną sumę owych komponentów. Zanim przejdziemy do omówienia technik służących &amp;amp;bdquo;wyłuskiwaniu&amp;amp;rdquo; komponent prześledźmy kilka symulacji i wnioski z nich płynące.&lt;br /&gt;
&lt;br /&gt;
==== Załamki i komponenty nie są tym samym.====&lt;br /&gt;
Tę samą krzywą można otrzymać na nieskończenie wiele sposobów  przez sumowanie rożnych kombinacji domniemanych komponentów. Przykładowy rysunek pokazuje, jak tę samą krzywą można złożyć z dwóch rożnych zestawów komponentów (kod wytwarzający przykładową symulację pokazany jest poniżej).&lt;br /&gt;
[[Plik:Sumowanie_komponentow1.png|center|thumb|600px| Panel a) przedstawia hipotetyczną krzywą ERP, panel b) jedna z możliwych dekompozycji sygnału w panelu a), panel c) inna możliwa dekompozycja sygnału z panelu a) ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show ,subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
&lt;br /&gt;
Fs = 1&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
&lt;br /&gt;
C1 = np.exp(-(t-100)**2/(2*30**2))&lt;br /&gt;
C2 = np.exp(-(t-200)**2/(2*50**2))&lt;br /&gt;
C3 = np.exp(-(t-350)**2/(2*100**2))&lt;br /&gt;
ERP = 0.5*C1-C2+C3&lt;br /&gt;
&lt;br /&gt;
C2p = np.concatenate((C2[0:200], np.ones(30), C2[200:700-30] ))&lt;br /&gt;
C3p = ERP - 0.5*C1 + C2p&lt;br /&gt;
ERP_v2 = 0.5*C1-C2p+C3p&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,1)&lt;br /&gt;
plot(t,ERP, t[::10],ERP_v2[::10],'g.')&lt;br /&gt;
ylabel('a)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,2)&lt;br /&gt;
plot(t,0.5*C1,t,-C2,t,C3)&lt;br /&gt;
ylabel('b)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,3)&lt;br /&gt;
plot(t,0.5*C1,t,-C2p,t,C3p)&lt;br /&gt;
ylabel('c)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.5])&lt;br /&gt;
&lt;br /&gt;
show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Zmiana jednej komponenty może powodować zmiany w amplitudzie i latencji więcej niż jednego załamka.====&lt;br /&gt;
Poniższy rysunek przedstawia sytuację gdy zmiana amplitudy jednego komponentu może znacząco wpływać na amplitudę i latencję innych załamków.&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sumowanie_komponentow2.png|center|thumb|768px| Panel a) przedstawia dwie hipotetyczne krzywe ERP, panel b) panel b i c komponenty z których powstały owe krzywe. Zmiana amplitudy komponentu oznaczonego kolorem powoduje zmianę amplitudy oznaczonych załamków ale także zmianę latencji wcześniejszego załamka. ]]&lt;br /&gt;
Poniżej kod odtwarzający powyższy przykład:&lt;br /&gt;
&amp;lt;source lang = python&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from __future__ import division&lt;br /&gt;
import numpy as np&lt;br /&gt;
from matplotlib.pyplot import plot, show, subplot, figure, title, xlabel, ylabel, ylim&lt;br /&gt;
&lt;br /&gt;
Fs = 1&lt;br /&gt;
t = np.arange(0,700)&lt;br /&gt;
&lt;br /&gt;
C1 = np.exp(-(t-100)**2/(2*30**2))&lt;br /&gt;
C2 = np.exp(-(t-200)**2/(2*50**2))&lt;br /&gt;
C3 = np.exp(-(t-350)**2/(2*100**2))&lt;br /&gt;
ERP1 = 0.5*C1-C2+C3&lt;br /&gt;
ERP2 = 0.5*C1-C2+1.5*C3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,1)&lt;br /&gt;
plot(t,ERP1,'b', t,ERP2,'g')&lt;br /&gt;
plot(t[np.argmin(ERP1)],np.min(ERP1),'r.' )&lt;br /&gt;
plot(t[np.argmax(ERP1)],np.max(ERP1),'m.' )&lt;br /&gt;
plot(t[np.argmin(ERP2)],np.min(ERP2),'r.' )&lt;br /&gt;
plot(t[np.argmax(ERP2)],np.max(ERP2),'m.' )&lt;br /&gt;
&lt;br /&gt;
ylabel('a)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,2)&lt;br /&gt;
plot(t,0.5*C1,'k',t,-C2,'k',t,C3,'b')&lt;br /&gt;
ylabel('b)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
subplot(3,1,3)&lt;br /&gt;
plot(t,0.5*C1,'k',t,-C2,'k',t,1.5*C3,'g')&lt;br /&gt;
ylabel('c)',rotation='horizontal')&lt;br /&gt;
ylim([-1, 1.6])&lt;br /&gt;
&lt;br /&gt;
show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Instrukcje do ćwiczeń =&lt;br /&gt;
&lt;br /&gt;
==Zadanie 1: uśrednianie symulowanych sygnałów==&lt;br /&gt;
w tym ćwiczeniu chcemy pokazać efekty:&lt;br /&gt;
# uśredniania sygnałów związanych fazowo z bodźcem i nieskorelowanych z bodźcem / wpływ liczby realizacji,&lt;br /&gt;
# uśredniania sygnałów z fluktuacją latencji,&lt;br /&gt;
# wpływ filtrów o różnych funkcjach odpowiedzi impulsowej na morfologię uśrednionego potencjału.&lt;br /&gt;
&lt;br /&gt;
===Sygnały testowe===&lt;br /&gt;
Proszę zaimplementować funkcje generujące następujące przebiegi czasowe (oznaczenia: ''F&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;'' &amp;amp;mdash; częstość próbkowania, ''T'' &amp;amp;mdash; czas trwania w sekundach, [[%C4%86wiczenia_1#Sygna.C5.82y_testowe|analogicznie do tego]]):&lt;br /&gt;
* sinusoida o zadanej częstości ''f'' i fazie &amp;lt;math&amp;gt;\phi&amp;lt;/math&amp;gt;: &amp;lt;tt&amp;gt;y = sin(f, phi, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* funkcja Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_1(t0, sigma, Fs, T) &amp;lt;/tt&amp;gt;&lt;br /&gt;
: &amp;lt;math&amp;gt;g_1(t) = \exp\left(-\frac{(t-t_0)^2}{2 \sigma^2}\right)&amp;lt;/math&amp;gt;,&lt;br /&gt;
* pochodną funkcji Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_2(t0, sigma, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* połowę funkcji Gaussa o zadanym położeniu i szerokości &amp;lt;tt&amp;gt;y = g_3(t0, sigma, Fs, T)&amp;lt;/tt&amp;gt;,&lt;br /&gt;
: &amp;lt;math&amp;gt;g_{3}(t) = \left\{ &lt;br /&gt;
\begin{array}{lll}&lt;br /&gt;
0 &amp;amp; \mathrm{dla}&amp;amp; t&amp;lt;t_0 \\&lt;br /&gt;
\exp\left(-\frac{(t-t_0)^2}{2 \sigma^2}\right)&amp;amp; \mathrm{dla}&amp;amp; t \ge t_0  &lt;br /&gt;
\end{array}&lt;br /&gt;
\right. &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W dalszych zadaniach tej sekcji przyjmiemy:&lt;br /&gt;
* ''T'' = 1 s,&lt;br /&gt;
* ''F&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;'' = 128 Hz,&lt;br /&gt;
* ''t''&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; = 0,3 s,&lt;br /&gt;
* &amp;amp;sigma; = 0,02 s.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu addytywnym: sygnał + szum===&lt;br /&gt;
Dla funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; i &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;  wykonaj ''N'' symulacji sygnału opisanego daną funkcją z dodanym szumem gaussowskim (&amp;lt;tt&amp;gt;numpy.random.randn&amp;lt;/tt&amp;gt;). Zaobserwuj zmianę wariancji uśrednianego sygnału wraz z ''N''.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu addytywnym: sygnał + szum + niezależna czynność rytmiczna===&lt;br /&gt;
Powtórz poprzednie symulacje dokładając w każdej realizacji sinusoidę o losowo wybranej fazie. Symulacje wykonaj dla różnych częstości sinusoidy, takich których połówka okresu zbliżona jest do szerokości funkcji Gaussa, oraz znacząco od niej różnych.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie w modelu z resetem fazy===&lt;br /&gt;
Zbuduj sygnał składający się z dwóch fragmentów sinusoidy o częstości ''f'': &lt;br /&gt;
* pierwszy fragment ma losową fazę,&lt;br /&gt;
* drugi fragment ma fazę równą 0.&lt;br /&gt;
Wykonaj ''N'' realizacji takiego sygnału, przy czym każda realizacja ma częstość losowaną z rozkładu Gaussa o średniej 10 i pewnej wariancji (czyli &amp;lt;math&amp;gt;f \in \mathrm{N}(10,\sigma)&amp;lt;/math&amp;gt;). &lt;br /&gt;
Uśrednij otrzymane realizacje. Zaobserwuj zależność średniej od ilości uśrednianych realizacji i od wariancji częstości.&lt;br /&gt;
&lt;br /&gt;
===Uśrednianie potencjału z fluktuacją latencji===&lt;br /&gt;
Wygeneruj sygnały składające się z funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt; z fluktuującą latencją, tzn. z wartością &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; pochodzącą z jakiegoś rozkładu prawdopodobieństwa. U nas dla ustalenia uwagi niech będzie to rozkład Gaussa. Wykonaj zestaw symulacji obrazujący zależność od ilości realizacji i od wielkości fluktuacji, mierzonej przez wariancję rozkładu. Czy jest związek pomiędzy wariancją fluktuacji &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; a szerokością załamków?&lt;br /&gt;
&lt;br /&gt;
===Wpływ filtrów===&lt;br /&gt;
# Zaprojektuj następujące filtry (przyjmij częstość próbkowania 128 Hz):&lt;br /&gt;
#* dolnoprzepustowy: Butterwortha z częstością odcięcia: 30, 40, 50 Hz, i rzędach od 1 do 5 (funkcja butter w module scipy.signal),&lt;br /&gt;
#* górnoprzepustowy: Butterwortha z częstością odcięcia: 0,1, 0,5, 2 i 5 Hz, i rzędach od 1 do 5,&lt;br /&gt;
#* notch: Czybyszewa II rodzaju z pasmem zaporowym ustawionym na 50 Hz, i rzędach od 1 do 3 (funkcja cheby2),&lt;br /&gt;
# Zbadaj funkcję odpowiedzi impulsowej i funkcję przenoszenia tych filtrów (w skali dB). Zaobserwuj jak długa jest odpowiedź impulsowa i jak daleko od częstości odcięcia zaburzone jest pasmo przenoszenia.&lt;br /&gt;
# Zastosuj powyższe filtry do funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;. Filtrowanie przeprowadź w jedną (lfilter) oraz w dwie strony (filtfilt). Zaobserwuj związek między zniekształceniem wprowadzanym przez filtr a funkcją odpowiedzi impulsowej filtru.&lt;br /&gt;
# W ćwiczeniu tym posłuż się symulowanymi sygnałami uzyskanymi z modelu addytywnego: &amp;amp;bdquo;sygnał+szum&amp;amp;rdquo;. Dla funkcji &amp;lt;math&amp;gt;g_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g_2&amp;lt;/math&amp;gt; albo &amp;lt;math&amp;gt;g_3&amp;lt;/math&amp;gt;  wykonaj ''N'' = 60 realizacji sygnału opisanego daną funkcją z dodanym szumem gaussowskim (&amp;lt;tt&amp;gt;numpy.random.randn&amp;lt;/tt&amp;gt;). Każdą z realizacji przefiltruj, a następnie uśrednij uzyskane sygnały.&lt;br /&gt;
&lt;br /&gt;
==Zadanie 2: rejestracje i analiza potencjałów wzrokowych==&lt;br /&gt;
&lt;br /&gt;
===Synchronizacja występowania bodźców z sygnałem EEG===&lt;br /&gt;
&lt;br /&gt;
Rejestracja potencjałów wywołanych jest przykładem pomiaru czynności elektrycznej mózgu w odpowiedzi na określony bodziec. W przypadku tego rodzaju pomiarów konieczna jest synchronizacja momentu wystąpienia bodźca z sygnałem EEG. Wzmacniacze do pomiaru czynności elektrycznej mózgu wyposażone są w specjalne wejścia, na które można podawać sygnał odpowiadający pojawianiu się bodźca. Jak pamiętamy z zeszłego semestru, wejście to (jak i podawany na nie sygnał) nazywamy trigerem (ang. ''trigger'' &amp;amp;mdash; spust, cyngiel, wyzwalacz). W najprostszym przypadku, bodziec moglibyśmy wyświetlać na monitorze komputerowym, a sygnał związany z jego wystąpieniem wysyłać przez któryś z portów komputera (LPT, COM) na wzmacniacz EEG. Niestety, obecnie dostępne i popularne systemy operacyjne, takie jak Windows czy Linux nie są systemami czasu rzeczywistego (http://pl.wikipedia.org/wiki/System_operacyjny_czasu_rzeczywistego). Od momentu wyświetlania bodźca na ekranie, do pojawiania się sygnału odpowiednim porcie komputerowym może upłynąć kilkadziesiąt milisekund i co gorsza czas ten zwykle jest losowy. W przypadku gdy wzmacniacz próbkuje sygnał z częstością 1000 Hz, moment wystąpienia bodźca możemy określić z dokładnością 1 ms, jednakże wspomniane opóźnienia w systemie operacyjnym uniemożliwiają to. Ponadto, jak dowiedzieliśmy się w rozdziale wstępnym [http://brain.fuw.edu.pl/edu-wiki/action/edit/EEG:Potencja%C5%82y_wywo%C5%82ane?section=T-1], pierwsze załamki związane z potencjałami wywołanymi pojawiają się już 10 ms po wystąpieniu bodźca. W związku z tym, losowe, rzędu kilkudziesięciu milisekund opóźnienia sygnału określającego moment pojawienia się bodźca względem jego rzeczywistego wystąpienia są niedopuszczalne.&lt;br /&gt;
Istnieją pewne techniki programowania, dzięki którym opisywane opóźnienia można zmniejszyć, jednakże są one bardzo trudne  do realizacji. Ponadto, standardowe porty komputera, takie jak LPT, czy COM zostały zaprojektowane przede wszystkim do sterowania urządzeniami zewnętrznymi, a nie ich zasilania. Przykładowo, jedna linia portu drukarkowego (LPT) może być obciążona prądem nie większym niż 5 mA, podczas gdy do zapalenie zwykłej diody LED potrzeba około 10 mA. Taki pobór prądu możliwy jest do uzyskania z portu USB, jednakże  jest on  wyjątkowo trudny do oprogramowania.  &lt;br /&gt;
W celu ominięcia powyższych niedogodności w Zakładzie Fizyki Biomedycznej UW w przeprowadzanych eksperymentach wykorzystywane są  mikrokontrolery [http://pl.wikipedia.org/wiki/Mikrokontroler], w szczególności ATmega16 i ATmega32.  Mikrokontrolery te wyposażone są w procesory o architekturze RISC [http://pl.wikipedia.org/wiki/RISC] i mocy obliczeniowej porównywalnej z szeroko stosowanym kiedyś w komputerach ZX Spectrum, Commodore, Amiga i Atari procesorem Z80. Oprócz jednostki centralnej mikrokontrolery zawierają   stałą pamięć FLASH przeznaczoną do przechowywania kodu programu, pamięć  RAM i pamięć EEPROM, liczniki 8- i 16-bitowe, komparatory, przetworniki analogowo-cyfrowe, porty wejścia/wyjścia, łącze RS232 (popularnie nazywane portem szeregowym) i układy przerwań.&lt;br /&gt;
&lt;br /&gt;
Mikrokontrolery wchodzące w skład zestawów pomiarowych na Pracowni EEG zawierają program, który umożliwia komunikację z nimi poprzez port szeregowy. Obecnie, komputery są coraz rzadziej wyposażane w porty szeregowe. Standard komunikacji RS-232, opracowany w 1962 roku  nadal jest jednak popularny i często wykorzystywany do komunikacji miedzy urządzeniami.  W celu połączenia komputera posiadającego tylko porty USB z mikrokontrolerem zastosowano przejściówkę USB/RS-232. &lt;br /&gt;
&lt;br /&gt;
Jak każde urządzenie w systemie Linuks, przejściówka USB/RS-232 widoczna jest jako plik, znajdujący się w katalogu &amp;lt;tt&amp;gt;/dev&amp;lt;/tt&amp;gt;. Nazwy plików obsługujących urządzenia szeregowe to &amp;lt;tt&amp;gt;ttyXY&amp;lt;/tt&amp;gt;, gdzie &amp;lt;tt&amp;gt;XY&amp;lt;/tt&amp;gt; to kolejny numer przydzielony do urządzenia szeregowego.&lt;br /&gt;
Do komunikacji komputera z mikroknotrolerem  w Zakładzie Fizyki Medycznej UW została napisana prosta biblioteka.  Jej użycie jest następujące:&lt;br /&gt;
* Po podłączeniu przejściówki USB/RS232 do komputera mikrokontrolera sprawdź jaki plik w katalogu &amp;lt;tt&amp;gt;/dev&amp;lt;/tt&amp;gt; został utworzony i przydzielony do urządzenia. &lt;br /&gt;
* Zaimportuj bibliotekę do komunikacji z mikrokontrolerem: &lt;br /&gt;
: &amp;lt;tt&amp;gt;import SerialPort as SP&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Otwórz plik powiązany z urządzeniem zewnętrznym:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp = SP.SerialPort(nazwa_pliku) &amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.open()&amp;lt;/tt&amp;gt;&lt;br /&gt;
gdzie przykładowa nazwa pliku wynosi &amp;lt;tt&amp;gt;/dev/ttyUSB0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Po włączeniu zasilania mikrokontrolera, diody podłączone do niego i wykorzystywane w eksperymencie z potencjałami wywołanymi będą zapalone. Następujące polecenie zgasi obydwie diody:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([0, 0])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Wydanie poniższego polecenia spowoduje, iż mikrokontroler zapali podłączoną do niego diodę numer 1 na czas 100 ms, zaś diodę numer 2 na 200 ms. Jednocześnie, w momencie włączenia jak i wyłączenia diody, sygnał z mikrokontrolera zostanie wysłany na 5-stykowe wejście AUX mikrokontrolera:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([100, 200])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Jeśli chcemy zapalić tylko diodę numer dwa, np. na czas 500 ms w programie podajemy następującą instrukcję:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.blinkP300([0, 500])&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Jeśli chcemy zakończyć komunikację z mikrokontrolerem piszemy:&lt;br /&gt;
: &amp;lt;tt&amp;gt;sp.close()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kod biblioteki do komunikacji z mikrokontrolerem:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: cp1250 -*-&lt;br /&gt;
import serial&lt;br /&gt;
import logging&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def to_hex_word(a):&lt;br /&gt;
    '''encodes a decimal number hexadecimally on two bytes'''&lt;br /&gt;
    return chr(int(a%256)) + chr(int(a/256))&lt;br /&gt;
&lt;br /&gt;
class SerialPort(object):&lt;br /&gt;
    def __init__(self, port_name):&lt;br /&gt;
        import serial&lt;br /&gt;
        try:&lt;br /&gt;
            self.port = serial.Serial(&lt;br /&gt;
                port=port_name,&lt;br /&gt;
                baudrate=9600,&lt;br /&gt;
                bytesize=serial.EIGHTBITS,&lt;br /&gt;
                parity=serial.PARITY_NONE,&lt;br /&gt;
                stopbits=serial.STOPBITS_ONE,&lt;br /&gt;
                xonxoff=False&lt;br /&gt;
                )&lt;br /&gt;
        except serial.SerialException:&lt;br /&gt;
            print(&amp;quot;Nieprawidłowa nazwa portu lub port zajęty.&amp;quot;)&lt;br /&gt;
            raise e&lt;br /&gt;
        self.close()&lt;br /&gt;
        &lt;br /&gt;
    def open(self):&lt;br /&gt;
        self.port.open()&lt;br /&gt;
&lt;br /&gt;
    def close(self):&lt;br /&gt;
        self.port.close()&lt;br /&gt;
&lt;br /&gt;
    def send(self, value):&lt;br /&gt;
        self.port.write(value)&lt;br /&gt;
                           &lt;br /&gt;
    def blinkSSVEP(self,d, p1, p2):&lt;br /&gt;
        '''&lt;br /&gt;
        d = list of frequencies;&lt;br /&gt;
        p1:p2 = ratio LED_on_time/LED_off_time&lt;br /&gt;
        if you want i-th LED to be OFF all the time send  d[i] = 0&lt;br /&gt;
        if you want i-th LED to be ON all the time send  d[i] = -1&lt;br /&gt;
        in these two cases p1 and p2 do not matter&lt;br /&gt;
        '''&lt;br /&gt;
        clock  = 62500&lt;br /&gt;
        factor = float(p1) / float(p1 + p2)&lt;br /&gt;
    &lt;br /&gt;
        str = chr(3) # 'SSVEP_RUN'&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(d)):&lt;br /&gt;
            # i-th LED OFF&lt;br /&gt;
            if d[i] == 0:                       &lt;br /&gt;
                str += to_hex_word(0) + to_hex_word(255) &lt;br /&gt;
            # i-th LED ON&lt;br /&gt;
            elif d[i] == -1:&lt;br /&gt;
                str += to_hex_word(255) + to_hex_word(0)&lt;br /&gt;
                #str = 'S'&lt;br /&gt;
                # i-th LED blinks d[i] times per second&lt;br /&gt;
                # p1:p2 = on_time:off_time in one blink&lt;br /&gt;
            else:&lt;br /&gt;
                period = clock/d[i]&lt;br /&gt;
                bright = int((clock/d[i]) * factor)&lt;br /&gt;
                dark = period - bright&lt;br /&gt;
                str += to_hex_word(bright) + to_hex_word(dark)&lt;br /&gt;
&lt;br /&gt;
        self.send(str)&lt;br /&gt;
&lt;br /&gt;
    def blinkP300(self,d):&lt;br /&gt;
        clock  = 62500&lt;br /&gt;
        str = chr(4) # 'P300_RUN'&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(d)):&lt;br /&gt;
            period = int(clock*d[i]/1000.0)&lt;br /&gt;
            str += to_hex_word(period)&lt;br /&gt;
            print(period)&lt;br /&gt;
&lt;br /&gt;
        self.send(bytes(str,'utf-8'))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zestaw eksperymentalny===&lt;br /&gt;
Zestaw składa się ze:&lt;br /&gt;
* wzmacniacza,&lt;br /&gt;
* stymulatora &amp;amp;mdash; układ zapalający i gaszący diodę w kontrolowany sposób,  &lt;br /&gt;
* izolowanego galwanicznie układu generującego impulsy odpowiadające gaszeniu i zapalaniu diody,  o wartościach dopasowanych do akceptowalnych przez wejścia AUX wzmacniacza,&lt;br /&gt;
* komputera: w tym eksperymencie komputer będzie służył do zaprogramowania stymulatora i do rejestracji sygnałów.&lt;br /&gt;
&lt;br /&gt;
===Wersja 1: obserwacja błyskającej diody  ===&lt;br /&gt;
&amp;lt;!--Proszę zapoznać się ze standardami rejestracji wzrokowych potencjałów wywołanych [http://www.gcu.ac.uk/media/gcalwebv2/theuniversity/academicschools/sls/psytimetables/SLS%20-%20VEP_Standard_2010.pdf] --&amp;gt;&lt;br /&gt;
Proszę zapoznać się z typowym wyglądem załamków w przypadku potencjałów wzrokowych, jaki jest przedstawiony na [https://static-content.springer.com/image/art%3A10.1007%2Fs10633-009-9195-4/MediaObjects/10633_2009_9195_Fig4_HTML.gif tym rysunku] (cały artykuł jest dostępny [http://link.springer.com/article/10.1007%2Fs10633-009-9195-4 tu]).&lt;br /&gt;
&amp;lt;!--[[Plik:Fig 4 VEP.jpg|thumb|320px|right|&amp;lt;figure id=&amp;quot;fig:zalamki_VEP&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;&lt;br /&gt;
&amp;lt;xr id=&amp;quot;fig:zalamki_VEP&amp;quot;&amp;gt;Rys. %i.&amp;lt;/xr&amp;gt; Schemat załamków rozpoznawanych we wzrokowych potencjach wywołanych (z pracy: J. V. Odom i in. &amp;amp;bdquo;ISCEV standard for clinical visual evoked potentials&lt;br /&gt;
(2009 update)&amp;amp;rdquo;, Doc Ophthalmol (2010), 120:111–119).]]&lt;br /&gt;
--&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
* Paradygmat: z odległości około 40 cm badany obserwuje błyski diody. Błyski powtarzają się co 1&amp;amp;plusmn;0,1 sekundy. Każdy błysk trwa 20 ms. Rejestrujemy 2 serie po 100 błysków. Częstość próbkowania 512 Hz.&lt;br /&gt;
** W pierwszej serii błyskamy tylko jedną diodą.&lt;br /&gt;
** W drugiej serii błyskamy dwiema diodami. &lt;br /&gt;
Pomiędzy seriami badany odpoczywa około 2 min. Diody powinny być ustawione na jednakową jasność błysków.&lt;br /&gt;
&lt;br /&gt;
* Pomiar&lt;br /&gt;
**Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%. [[Plik:Glowka10-20 ERPy.svg|thumb|600px|right]]&lt;br /&gt;
** Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
** Montujemy także elektrodę FCz (na linii centralnej pomiędzy Fz a Cz), będziemy jej używać w montażu i w czasie analizy jako referencji.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +400 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy wycięte sygnały.&lt;br /&gt;
# Rysujemy średni potencjał we wszystkich kanałach.&lt;br /&gt;
# Identyfikujemy załamki N2 i P2. Mierzymy amplitudę P2 jako różnicę między ekstremalną wartością załamka P2 a ekstremalną wartością załamka N2. &lt;br /&gt;
&lt;br /&gt;
[[Plik:ZalamkiN2_P2.png‎|thumb|600px|right|  Uśredniony potencjał wywołany dla serii 1 i 2 na kanale T5 z zaznaczonymi załamkami N2 i P2. Na osi poziomej czas [s] natomiast na pionowej amplituda [μV].]]&lt;br /&gt;
Pomiar wykonujemy dla obu serii błysków.&lt;br /&gt;
&lt;br /&gt;
Pytanie: Czy intensywność bodźca wpływa na amplitudę potencjału P2?&lt;br /&gt;
Jak stwierdzić czy amplitudy załamków P2 istotnie różnią się pomiędzy seriami?&lt;br /&gt;
&lt;br /&gt;
Musimy przeprowadzić test statystyczny. Możemy skonstruować go np. tak:&lt;br /&gt;
Mamy dwa warunki I i II. Jako statystykę przyjmiemy różnicę pomiędzy amplitudą załamka zmierzoną w serii z dwoma diodami (P2&amp;lt;sub&amp;gt;II&amp;lt;/sub&amp;gt;) a amplitudą zmierzoną w serii z jedną diodą (P2&amp;lt;sub&amp;gt;I&amp;lt;/sub&amp;gt;):&lt;br /&gt;
: ''S'' = P2&amp;lt;sub&amp;gt;II&amp;lt;/sub&amp;gt; &amp;amp;minus; P2&amp;lt;sub&amp;gt;I&amp;lt;/sub&amp;gt;&lt;br /&gt;
Postawmy hipotezę zerową, że nie ma różnicy w amplitudzie pomiędzy warunkiem II a I oraz hipotezę alternatywną, że różnica taka występuje.&lt;br /&gt;
: H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;: ''S'' = 0&lt;br /&gt;
: H&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;: ''S'' &amp;amp;ne; 0&lt;br /&gt;
Zgodnie z H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; dla wartości ''S'' nie ma różnicy czy realizacja została zarejestrowana w warunkach I czy II, zatem można losowo poprzypisywać numery warunków do realizacji i w ten sposób uzyskać rozkład statystyki ''S'' pod warunkiem prawdziwości H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;, czyli obliczyć średnie potencjały dla &amp;amp;bdquo;pomieszanych&amp;amp;rdquo; tagów, wyliczyć średnie potencjały dla sztucznie wygenerowaych grup, i wyliczyć różnicę amplitud dla tych średnich, czyli wartość statystyki dla hipotezy H&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Zaimplementuj test permutacyjny zgodny z powyższą koncepcją.&lt;br /&gt;
&lt;br /&gt;
===Wersja 2: obserwacja habituacji / uśrednianie w blokach ===&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
# Paradygmat: &lt;br /&gt;
#* z odległości około 40 cm badany obserwuje błyski diody. &lt;br /&gt;
#* Błyski powtarzają się co 0,5 sekundy. &lt;br /&gt;
#* Rejestrujemy 60 serii po 15 błysków.  &lt;br /&gt;
#* Pomiędzy seriami badany odpoczywa około 10 sekund.&lt;br /&gt;
# Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%.&lt;br /&gt;
#* Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
#* Montujemy także elektrodę FCz (na linii centralnej pomiędzy Fz a Cz), będziemy jej używać w montażu i w czasie analizy jako referencji.&lt;br /&gt;
#* Częstość próbkowania 512 Hz.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +600 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy wycięte sygnały o tym samym numerze wewnątrz serii.&lt;br /&gt;
# Rysujemy serie 15 uśrednionych potencjałów dla tego kanału, który wykazywał najsilniejszy potencjał w pierwszej wersji eksperymentu.&lt;br /&gt;
&lt;br /&gt;
==Zadanie 3: rejestracja i analiza potencjału P3 ==&lt;br /&gt;
==== Rejestracja ====&lt;br /&gt;
# Paradygmat: &lt;br /&gt;
#* z odległości około 40 cm badany obserwuje błyski diody. &lt;br /&gt;
#* Błyski diody nr 1 powtarzają się co 1&amp;amp;plusmn;0,1 sekundy. &lt;br /&gt;
#* W losowych realizacjach zapalana jest także dioda nr 2. &lt;br /&gt;
#* Proporcja pomiędzy ilością błysków pojedynczych i podwójnych powinna wynosić 10:2, przy czym błyski podwójne muszą być odseparowane co najmniej jednym błyskiem pojedynczym. &lt;br /&gt;
#* Czas zapalenia diod, tak jak w poprzednich eksperymentach, wynosi 20 ms. &lt;br /&gt;
#* Zadaniem badanego jest liczenie liczby błysków podwójnych.&lt;br /&gt;
#* Wykonujemy tyle realizacji aby zarejestrować 50 powtórzeń podwójnych błysków. &lt;br /&gt;
# Zakładamy czepek i elektrody w systemie 10-20, dbamy o to by opory pomiędzy elektrodami były poniżej 5 k&amp;amp;Omega; i różnice pomiędzy oporami różnych elektrod nie przekraczały 20%.&lt;br /&gt;
#* Elektrodę GND mocujemy w otworze czepka odpowiadającym pozycji AFz (na linii centralnej 10% w stronę nosa od elektrody Fz) &lt;br /&gt;
#* Montujemy także elektrody M1 i M2, będziemy ich używać w montażu i w czasie analizy jako referencji typu połączone uszy.&lt;br /&gt;
#* Częstość próbkowania 512 Hz.&lt;br /&gt;
&lt;br /&gt;
==== Analiza ====&lt;br /&gt;
# Filtrujemy sygnał w paśmie 0,1-20 Hz.&lt;br /&gt;
# Z ciągłego zapisu wycinamy fragmenty od &amp;amp;minus;300 ms do +600 ms (zero oznacza moment wystąpienia bodźca). W czasie wycinania badamy wycinane fragmenty pod względem zakresu amplitudy (wszystkie kanały powinny mieć amplitudę w granicach &amp;amp;plusmn;75 &amp;amp;mu;V) i zawartości artefaktów od mrugania (w tym celu trzeba oglądając sygnał w SVAROG-u ustalić próg na amplitudę sygnału w kanałach Fp1 i Fp2).&lt;br /&gt;
# Uśredniamy osobno realizacje błysków pojedynczych i błysków podwójnych.&lt;br /&gt;
# Nakładamy na siebie na rysunkach oba typy średnich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ćwiczenie dodatkowe: P300 BCI==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wykorzystujemy elektrody z systemu 10-10 umieszczone nad korą wzrokową: P07, O1, O2, PO8, PO3, PO4, Pz, Cz.&lt;br /&gt;
&lt;br /&gt;
Uruchamiamy &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
obci_gui --presets eeg_workshop&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i z guzika &amp;amp;bdquo;select amplifier&amp;amp;rdquo; wybieramy właściwy wzmacniacz.&lt;br /&gt;
&lt;br /&gt;
Do kontroli jakości sygnału możemy uruchomić Svaroga.&lt;br /&gt;
&lt;br /&gt;
Dane z kalibracji zapisują się w pliku test1 w katalogu domowym użytkownika, z labiryntu w pliku test2.&lt;br /&gt;
&lt;br /&gt;
Po zakończeniu kalibracji pojawia się napis &amp;amp;bdquo;Trwają obliczenia&amp;amp;rdquo; lub podobny. Odczekujemy kilka minut, aż skończy się peer &amp;amp;bdquo;Calibration&amp;amp;rdquo; (widoczny w obci_gui) i zamykamy okienko klawiszami Alt-F4 lub zatrzymując scenariusz guzikiem &amp;amp;bdquo;Stop&amp;amp;rdquo;. W katalogu domowym pojawi się plik z wynikami kalibracji, co pozwala na uruchomienie scenariusza &amp;amp;bdquo;labirynt&amp;amp;rdquo;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Po zebraniu danych, przed wczytaniem ich do Svaroga należy w tym samym katalogu uruchomić skrypt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.obci_signal_processing.tags import tags_file_writer&lt;br /&gt;
from obci.analysis.obci_signal_processing.read_manager import ReadManager&lt;br /&gt;
&lt;br /&gt;
def main(): &lt;br /&gt;
	file_name = 'test1'&lt;br /&gt;
	&lt;br /&gt;
	mgr = ReadManager(&lt;br /&gt;
		file_name + '.obci.xml',&lt;br /&gt;
		file_name + '.obci.raw',&lt;br /&gt;
		file_name + '.obci.tag')&lt;br /&gt;
	&lt;br /&gt;
	tags = mgr.get_tags()&lt;br /&gt;
	for i in xrange(0, len(tags)):&lt;br /&gt;
		if tags[i]['desc']['index'] == tags[i]['desc']['target']:&lt;br /&gt;
			tags[i]['name'] = 'blink_target'&lt;br /&gt;
		else:&lt;br /&gt;
			tags[i]['name'] = 'blink'&lt;br /&gt;
			&lt;br /&gt;
	tags_writer = tags_file_writer.TagsFileWriter(file_name + '.obci.tag')&lt;br /&gt;
	for tag in tags:&lt;br /&gt;
		tags_writer.tag_received(tag)		&lt;br /&gt;
	tags_writer.finish_saving(0)	&lt;br /&gt;
 &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:Halotron2_new.png&amp;diff=7795</id>
		<title>Plik:Halotron2 new.png</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:Halotron2_new.png&amp;diff=7795"/>
		<updated>2018-06-05T20:35:58Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7794</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7794"/>
		<updated>2018-06-05T20:35:27Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Hallotron */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; motor-rg.py&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; dtoa.py&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; atod.py&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn KSP2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2_new.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:Tranzystor.png&amp;diff=7783</id>
		<title>Plik:Tranzystor.png</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:Tranzystor.png&amp;diff=7783"/>
		<updated>2018-05-30T07:20:28Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: Gbernatowicz przesłał nową wersję Plik:Tranzystor.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7782</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7782"/>
		<updated>2018-05-30T07:19:30Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Tranzystor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; motor-rg.py&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; dtoa.py&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; atod.py&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn KSP2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7738</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7738"/>
		<updated>2018-05-15T18:57:47Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przetwornik analogowo-cyfrowy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; motor-rg.py&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; dtoa.py&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; atod.py&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7737</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7737"/>
		<updated>2018-05-15T18:57:25Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przetwornik cyfrowo-analogowy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; motor-rg.py&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; dtoa.py&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7736</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7736"/>
		<updated>2018-05-15T18:55:50Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Sterownik silnika prądu stałego */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; motor-rg.py&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7735</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7735"/>
		<updated>2018-05-15T18:54:57Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Otwarty Kolektor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; ocol-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7734</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7734"/>
		<updated>2018-05-15T18:52:35Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Diody + Przyciski */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; butled-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7733</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7733"/>
		<updated>2018-05-15T18:52:09Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Diody */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; leds-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7732</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7732"/>
		<updated>2018-05-15T18:51:17Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przyciski */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
# FileName -&amp;gt; buttons-rg.py&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7731</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7731"/>
		<updated>2018-05-15T18:50:04Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Diody + Przyciski */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało gaszenie 6 diody, puszczanie 3 przycisku powodowało zapalenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7730</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7730"/>
		<updated>2018-05-15T18:49:25Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przyciski */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech zer pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch zer i jedynki pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało zapalanie 6 diody, puszczanie 3 przycisku powodowało gaszenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7724</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7724"/>
		<updated>2018-05-09T06:48:49Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym i poziomym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import KinectDataReader&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '......'&lt;br /&gt;
file_name = '......'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7709</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7709"/>
		<updated>2018-04-24T10:54:09Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przetwornik analogowo-cyfrowy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech jedynek pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch jedynek i zera pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało zapalanie 6 diody, puszczanie 3 przycisku powodowało gaszenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7708</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7708"/>
		<updated>2018-04-24T10:52:32Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przetwornik cyfrowo-analogowy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech jedynek pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch jedynek i zera pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało zapalanie 6 diody, puszczanie 3 przycisku powodowało gaszenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2835', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7707</id>
		<title>Nowe technologie w fizyce biomedycznej/Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Raspberry_Pi&amp;diff=7707"/>
		<updated>2018-04-23T11:16:25Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przyciski */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Raspberry Pi =&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi==&lt;br /&gt;
Raspberry Pi to mała (wymiary: 85.60 mm × 53.98 mm, przy wadze 45 gramów) platforma komputerowa stworzona przez brytyjską organizację charytatywną &amp;quot;Fundację Raspberry Pi&amp;quot; w celach edukacyjnych. Miała za zadanie ułatwić uczniom naukę programowania oraz sterowania zewnętrznymi urządzeniami. &lt;br /&gt;
&lt;br /&gt;
Raspberry Pi zasilany jest napięciem 5V poprzez gniazdo microUSB. Niski pobór mocy jest jedną z przyczyn częstego wykorzystania Raspberry w robotyce. Komputer ten to w głównej mierze układ Broadcom:&lt;br /&gt;
*512 MB RAMu&lt;br /&gt;
*procesor graficzny &lt;br /&gt;
*procesor taktowany zegarem 700MHz&lt;br /&gt;
Raspberry Pi nie posiada wbudowanego dysku twardego - korzysta z karty SD, którą wykorzystuje do załadowania systemu operacyjnego (Raspbian - specjalnie dedykowana wersja Debiana) i przechowywania danych. Do tego komputera można podłączyć urządzenia zewnętrzne poprzez łącza:&lt;br /&gt;
*HDMI - monitor&lt;br /&gt;
*ethernet - internet&lt;br /&gt;
*USB - klawiatura, myszka, itp.&lt;br /&gt;
Główną cechą Raspberry Pi jest zestaw połączeń GPIO (General Purpose Input Output), które pozwalają na wysyłanie i odbieranie sygnałów cyfrowych (z i do urządzeń zewnętrznych takich jak motorki, czujniki, diody, przełączniki itd.).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Raspberry.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Raspberry Pi. Źródło: https://en.wikipedia.org/wiki/Raspberry_Pi]]&lt;br /&gt;
&lt;br /&gt;
==Gertboard==&lt;br /&gt;
&lt;br /&gt;
Gertboard jest to moduł rozszerzający możliwości komputera Raspberry Pi. Jego instrukcja obsługi znajduje się pod adresem: [https://www.farnell.com/datasheets/1683444.pdf]. Do obsługi płytki Gertboard będziemy korzystac z modułu RPi napisanego w języku Python [https://pypi.python.org/pypi/RPi.GPIO]. Płytka ta posiada m.in.:&lt;br /&gt;
*sterownik silnika prądu stałego&lt;br /&gt;
*12 buforowanych portów wyjścia/ wejścia&lt;br /&gt;
*3 przyciski typu tact-switch&lt;br /&gt;
*6 wejść typu otwarty kolektor&lt;br /&gt;
*dwukanałowy 10 bitowy przetwornik analogowo-cyfrowy&lt;br /&gt;
*dwukanałowy 8, 10 lub 12 bitowy przetwornik cyfrowo-analogowy&lt;br /&gt;
Płytka ta podłączana jest bezpośrednio do pinów GPIO w Raspberry, skąd też pobiera zasilanie.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Aby zasilić płytkę Gertboard napięciem 3,3 V należy umieścić zworkę w pozycji pokazanej na poniższym rysunku (prawy dolny róg płytki).&lt;br /&gt;
&lt;br /&gt;
[[Plik:power.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Miejsce wpięcia złączki, w celu zasilenia płytki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Połączeń na płytce dokonywać będziemy korzystając ze zworek (małe czarne elementy 'zwierające' piny blisko siebie) oraz złączek (kabelki łączące piny leżące dalej od siebie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:złączki.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przewody łączące piny na płytce Gertboard: zworki i złączki. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Rząd pinów GPIO (oznaczonych czarną ramką) jest &amp;quot;łącznikiem&amp;quot; płytki Gaertboard z Raspberry Pi. Mamy zatem 17 pinów, które mogą spełniać funkcje wejścia lub wyjścia dla sygnału cyfrowego (w zależności od tego do czego je podłączymy). Przykładem może być podpięcie do nich buforowanych portów wejścia/wyjścia opisanych poniżej.&lt;br /&gt;
&lt;br /&gt;
==Buforowane porty I/O==&lt;br /&gt;
&lt;br /&gt;
Ramką nr 2 zaznaczono 12 portów wejścia/wyjścia (I/O), których sygnał po przejściu przez układ buforujący (ramki nr 3,4,5) można przekazać do/od Raspberry Pi poprzez połączenie odpowiadających im portów z obszaru ramki nr 1 z portami GPIO. Do każdego z portów I/O przypisana jest dioda (tuż pod portami w ramce nr 2), która wskazuje obecny stan logiczny danego portu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buffers.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Zaznaczone obszary buforowanych portów wejścia/wyjścia. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Każdy z 12 portów I/O posiada swój obwód buforowy (schemat przedstawiono poniżej), który składa się z buforów przepuszczających prąd tylko w jednym kierunku, oporników, diody LED  oraz miejsc łączeniowych. Jeśli połączymy obwód w miejscu 'in', sygnał będzie przekazywany tylko w kierunku od portów I/O do Raspberry Pi. Jeśli umieścimy zworkę w miejscu 'out', sygnał będzie przekazywany tylko w kierunku od Raspberry Pi do portów I/O.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:bufor.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu buforowego. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Na płytce Gertboard porty wejścia/wyjścia o numerach od 1-4 mają swój obwód buforowy w chipie U3 oznaczonym ramką nr 3, porty 5-8 w chipie U4 zaznaczonym ramką nr 4, porty 9-12 w chipie U5 zaznaczonym ramką nr 5. Miejsca połączenia obwodu buforowego 'in' znajdują się w dolnej połowie chipa, natomiast miejsca połączenia obwodu buforowego 'out' w górnej połowie chipa. Poniższy obrazek prezentuje takie ustawienie zworek, dla którego porty 1,2,3 będą ustawione jako 'wyjście', natomiast porty 10,11 jako 'wejście'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:in_out.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Lokalizacja wpięcia zworek. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z powyższymi oznaczeniami studenci mają za zadanie wykonać połączenia na desce Gertboard tak aby:&lt;br /&gt;
*buforowany port BUF_3 był portem wyjścia, na który sygnał jest przekazywany przez port GP22&lt;br /&gt;
*buforowany port BUF_8 był portem wejścia, który przekazuje sygnał na port GP7&lt;br /&gt;
*buforowany port BUF_10 był portem wyjścia, na który sygnał jest przekazywany przez port GP10&lt;br /&gt;
*buforowany port BUF_11 był portem wejścia, który przekazuje sygnał na port GP25&lt;br /&gt;
&lt;br /&gt;
== Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Deska Gertboard posiada 3 przyciski, które są podłączone do portów B1, B2 oraz B3. Schemat obwodu elektrycznego został przedstawiony poniżej. Jak widać, podczas przyciśnięcia przycisku port wejściowy do Raspberry zostaje połączony poprzez opornik z uziemieniem, co skutkuje odczytaniem logicznej wartości zero. Aby na bieżąco kontrolować zmiany spowodowane przyciskiem, można wpiąć zworkę w pozycji 'out' co sprawi, że stan logiczny przycisku będzie odzwierciedlany przez diodę LED (konkretną dla danego przycisku). Podczas korzystania z przycisku jako wejścia nie wpinamy zworki w miejscu 'in', ponieważ bufor wejściowy będzie zakłócał działanie przycisku.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: przyciski można połączyć z dowolnymi portami GPIO, oprócz GP0 oraz GP1 (porty te mają dodatkowo wbudowane oporniki 1,8 k&amp;amp;Omega;)&lt;br /&gt;
&lt;br /&gt;
[[Plik:button.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu z przyciskiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Test przycisków. Wpinamy zworki oraz złączki w sposób przedstawiony na schemacie poniżej. Następnie uruchamiamy program 'buttons-rg.py'. Program ten będzie wyświetlał w terminalu stan trzech przycisków (gdzie 0 odpowiada wciśniętemu przyciskowi) za każdym razem gdy ulegnie on zmianie (po 19 zmianach stanów przycisków program zakończy działanie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                # initialise RPi.GPIO&lt;br /&gt;
for i in range(23,26):                                # set up ports 23-25 &lt;br /&gt;
    GPIO.setup(i, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # as inputs pull-ups high &lt;br /&gt;
                                                      # (if pin is not connected - input is pulled-up high as 1)      &lt;br /&gt;
&lt;br /&gt;
# Print  Instructions appropriate for the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard buttons test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;Optionally, if you want the LEDs to reflect button state do the following:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B1&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B2&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U3-out-B3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                      # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                          # read inputs until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(25), GPIO.input(24), GPIO.input(23)]&lt;br /&gt;
        for i in range(0,3):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot;&lt;br /&gt;
        # dump current status values in a variable&lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1],status_list[2])) &lt;br /&gt;
        if current_status != previous_status:         # if that variable not same as last time &lt;br /&gt;
            print current_status                      # print the results &lt;br /&gt;
            previous_status = current_status          # update status variable for next comparison&lt;br /&gt;
            button_press += 1                         # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                             # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                    # resets all GPIO ports used by this program&lt;br /&gt;
GPIO.cleanup()                                        # on exit, reset all GPIO ports &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po zapoznaniu się z implementacją powyższego przykładu studenci mają za zadanie tak zmodyfikować program aby:&lt;br /&gt;
*po naciśnięciu jednocześnie trzech przycisków w terminalu zamiast trzech jedynek pojawiała się linia wykrzykników&lt;br /&gt;
*po naciśnięciu jednocześnie dwóch przycisków w terminalu zamiast dwóch jedynek i zera pojawiała się linia znaków zapytania&lt;br /&gt;
&lt;br /&gt;
== Diody ==&lt;br /&gt;
&lt;br /&gt;
Aby przetestować działanie diod skorzystamy z programu 'leds_rg.py'. Najpierw łączymy odpowiednie porty tak jak pokazano na poniższym schemacie, następnie uruchamiamy program. W zależności od wybranej procedury sterowania diodami będą się one zapalać/gasić w prawo/w lewo. Studenci mają za zadanie zapoznać się z implementacją.&lt;br /&gt;
&lt;br /&gt;
!Uwaga: porty GP14 i GP15 pozostają bez połączenia, ponieważ są one pierwotnie ustawione przez system operacyjny na mod UART i lepiej ich nie przestawiać na mod OUTPUT&lt;br /&gt;
&lt;br /&gt;
[[Plik:leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
if GPIO.RPI_REVISION == 1:                          # check Pi Revision to set port 21/27 correctly&lt;br /&gt;
    # define ports list for Revision 1 Pi&lt;br /&gt;
    ports = [25, 24, 23, 22, 21, 18, 17, 11, 10, 9, 8, 7]&lt;br /&gt;
else:&lt;br /&gt;
    # define ports list all others&lt;br /&gt;
    ports = [25, 24, 23, 22, 27, 18, 17, 11, 10, 9, 8, 7]   &lt;br /&gt;
ports_rev = ports[:]                                # make a copy of ports list&lt;br /&gt;
ports_rev.reverse()                                 # and reverse it as we need both&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)                  # set up ports for output&lt;br /&gt;
&lt;br /&gt;
def led_drive(reps, multiple, direction):           # define led_function:&lt;br /&gt;
    for i in range(reps):                           # (repetitions, single/multiple, direction)&lt;br /&gt;
        for port_num in direction:                  &lt;br /&gt;
            GPIO.output(port_num, 1)                # switch on an led&lt;br /&gt;
            sleep(0.11)                             # wait for ~0.11 seconds&lt;br /&gt;
            if not multiple:                        # if we're not leaving it on&lt;br /&gt;
                GPIO.output(port_num, 0)            # switch it off again&lt;br /&gt;
&lt;br /&gt;
# Print Wiring Instructions appropriate to the board&lt;br /&gt;
print &amp;quot;These are the connections for the Gertboard LEDs test:&amp;quot;                &lt;br /&gt;
print &amp;quot;jumpers in every out location (U3-out-B1, U3-out-B2, etc)&amp;quot;&lt;br /&gt;
print &amp;quot;GP25 in J2 --- B1 in J3 \nGP24 in J2 --- B2 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3 \nGP22 in J2 --- B4 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP21 in J2 --- B5 in J3 \nGP18 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP17 in J2 --- B7 in J3 \nGP11 in J2 --- B8 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP10 in J2 --- B9 in J3 \nGP9 in J2 --- B10 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP8 in J2 --- B11 in J3 \nGP7 in J2 --- B12 in J3&amp;quot; &lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:                                              &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: forwards&lt;br /&gt;
    led_drive(1, 0, ports)                  &lt;br /&gt;
    # one repetition, switching off led before next one comes on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports_rev)&lt;br /&gt;
    # one repetition, leaving each led on, direction: forwards&lt;br /&gt;
    led_drive(1, 1, ports)&lt;br /&gt;
    # one repetition, leaving each led on, direction: backwards&lt;br /&gt;
    led_drive(1, 0, ports)        &lt;br /&gt;
except KeyboardInterrupt:                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                    # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby sterować diodami w następujący sposób:&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i gasną tuż przed zapaleniem następnej)&lt;br /&gt;
*kolejno w prawą stronę zapalają się parzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*kolejno w lewą stronę zapalają się nieparzyste numery diod (i pozostają zapalone)&lt;br /&gt;
*wszystkie diody są zgaszone&lt;br /&gt;
&lt;br /&gt;
== Diody + Przyciski ==&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić dotychczasowe zrozumienie materiału, kolejne zadanie polega na połączeniu wiedzy na temat działania przycisków oraz diod. Docelowo chcemy aby naciskanie 3 przycisku powodowało zapalanie 6 diody, puszczanie 3 przycisku powodowało gaszenie 6 diody. Każda zmiana statusu przycisku oraz diody ma być wypisana w terminalu. &lt;br /&gt;
&lt;br /&gt;
Jak pamiętamy z rozdziału o przyciskach, aby sygnał z guzika był wejściem do Raspberry, nie wpinamy zworki w miejscu 'in'. Sygnał z przycisku 3 jest automatycznie przekazywany do portu B3, który z kolei został połączony z portem GP23 w Raspberry za pomocą złączki. Zatem port GP23 dostaje informację o zmianie stanu przycisku. &lt;br /&gt;
&lt;br /&gt;
Następnie chcemy aby ta zmiana stanu wartości logicznej przycisku była widoczna jako zapalanie/gaszenie diody. Najprostszą sytuacją jest wyświetlanie stanu 3 przycisku na 3 diodzie (zgodnie z poprzednim rozdziałem wystarczyłoby ustawić zworkę w miejscu 'out' portu B3). Jednak sprawa się nieco komplikuje, gdy stan przycisku ma być odzwierciedlony na 6 diodzie. Trzeba zatem sygnał wyjściowy ('out' B3) przekierować na port BUF_6. Wtedy dioda 6 będzie pokazywać stan logiczny portu 6.&lt;br /&gt;
&lt;br /&gt;
Jednak to jeszcze nie koniec utrudnień. Dodatkowo chcemy aby stan diody 6 był sczytywany przez Raspberry Pi. Zatem musimy wskazać, że port BUF_6 jest sygnałem wejściowym do Raspberry (zworka 'in' na B6), który zostanie przesłany na port GP22 (złączka między B6 a GP22). &lt;br /&gt;
&lt;br /&gt;
Gdy schemat połączeń jest jasny można go zrealizować, a następnie uruchamić program 'butled_rg.py'.&lt;br /&gt;
&lt;br /&gt;
[[Plik:buttons_leds.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przycisków oraz diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                                            # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)                 # set up port 23 for INPUT pulled-up high&lt;br /&gt;
GPIO.setup(22, GPIO.IN)                                           # set up port 22 for normal INPUT no pullup&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections you must make on the Gertboard for this test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP23 in J2 --- B3 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;GP22 in J2 --- B6 in J3&amp;quot;&lt;br /&gt;
print &amp;quot;U3-out-B3 pin 1 --- BUF6 in top header&amp;quot;&lt;br /&gt;
print &amp;quot;jumper on U4-in-B6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
button_press = 0                                                  # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while button_press &amp;lt; 20:                                      # read inputs constantly until 19 changes are made&lt;br /&gt;
        status_list = [GPIO.input(23), GPIO.input(22)]            # put input values in a list variable&lt;br /&gt;
        for i in range(0,2):&lt;br /&gt;
            if status_list[i]:&lt;br /&gt;
                status_list[i] = &amp;quot;1&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                status_list[i] = &amp;quot;0&amp;quot; &lt;br /&gt;
        current_status = ''.join((status_list[0],status_list[1])) # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:                     # if that variable not same as last time&lt;br /&gt;
            print current_status                                  # print the results &lt;br /&gt;
            previous_status = current_status                      # update status variable for next comparison&lt;br /&gt;
            button_press += 1                                     # increment button_press counter&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                                         # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                                # resets all GPIO ports&lt;br /&gt;
GPIO.cleanup()                                                    # on exit, reset  GPIO ports used by program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Płytka uniwersalna ==&lt;br /&gt;
&lt;br /&gt;
Płytka uniwersalna to narzędzie ułatwiające samodzielne i szybkie tworzenie obwodów elektronicznych. Jej angielska nazwa ''breadboard'' wskazuje na historyczne korzenie tego narzędzia. Oryginalnie (lata 20-te XX wieku) były to dosłownie deski do krojenia chleba, do których amatorzy wczesnej elektroniki (np. radia) przymocowywali przewody i inne elementy elektroniczne za pomocą gwoździ. Współcześnie, jednym z rodzajów płytek uniwersalnych jest płytka stykowa, która nie wymaga przylutowywania elementów, a jedynie umieszczenia ich w odpowiednich otworach. Oznaczone linie czerwone i niebieskie, to rzędy otworów połączonych ze sobą. Dodatkowo kolumny otworów wzdłuż krótszego boku płytki również są ze sobą połączone. &lt;br /&gt;
&lt;br /&gt;
[[Plik:breadboard.jpg|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka uniwersalna stykowa. Źródło: https://pl.wikipedia.org/wiki/Plik:400_points_breadboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Zadanie 1 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować obwód przedstawiony na schemacie. Diodę czerwoną wpinamy dłuższą nóżką w stronę +, krótszą w stronę -, natomiast opornik wybieramy o oporności 0,6 k&amp;amp;Omega;. Docelowo,  dioda na płytce uniwersalnej ma być sterowana sygnałem pochodzącym z portu BUF_1 (czyli sygnałem generowanym przez Raspberry Pi podawanym na port GP25):&lt;br /&gt;
*dioda ma zostać zapalona na czas 5 sekund&lt;br /&gt;
*następnie zgaszona na 5 sekund&lt;br /&gt;
*na koniec ma być zapalana i wygaszana co 1 sekundę (10-cio krotnie).&lt;br /&gt;
&lt;br /&gt;
[[Plik:board1.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 1]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.OUT)                            # set up ports for output&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    GPIO.output(25, 1)   &lt;br /&gt;
    sleep(5) &lt;br /&gt;
    GPIO.output(25, 0)&lt;br /&gt;
    sleep(5) &lt;br /&gt;
    for i in range(10):&lt;br /&gt;
        GPIO.output(25, 1)   &lt;br /&gt;
        sleep(1) &lt;br /&gt;
        GPIO.output(25, 0)&lt;br /&gt;
        sleep(1) &lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Zadanie 2 ===&lt;br /&gt;
&lt;br /&gt;
Korzystając z płytki uniwersalnej należy zbudować układ przedstawiony na schemacie. Opornik dobieramy o oporności 1 k&amp;amp;Omega;. Docelowo chcemy sczytywać (i wyświetlać w terminalu) stan portu BUF_1, który to będzie regulowany poprzez zbudowany przez nas przełącznik.&lt;br /&gt;
&lt;br /&gt;
[[Plik:board2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do Zadania 2]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # set up ports for input&lt;br /&gt;
&lt;br /&gt;
change = 0                                          # set intial values for variables&lt;br /&gt;
previous_status = ''&lt;br /&gt;
&lt;br /&gt;
try:                                        &lt;br /&gt;
    while change &amp;lt; 10:                              # read inputs until 9 changes are made&lt;br /&gt;
        status_list = GPIO.input(25)&lt;br /&gt;
        current_status = status_list               # dump current status values in a variable&lt;br /&gt;
        if current_status != previous_status:      # if that variable not same as last time&lt;br /&gt;
            print current_status                   # print the results &lt;br /&gt;
            previous_status = current_status       # update status variable for next comparison&lt;br /&gt;
            change += 1                            # increment change counter&lt;br /&gt;
except KeyboardInterrupt:                          # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                 # clean up GPIO ports on CTRL+C&lt;br /&gt;
GPIO.cleanup()                                     # clean up GPIO ports on normal exit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;\source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Otwarty Kolektor ==&lt;br /&gt;
&lt;br /&gt;
Do tej pory, za pomocą Raspberry Pi, sterowaliśmy zewnętrznymi &amp;quot;urządzeniami&amp;quot; takimi jak diody. W tym celu wystarczało dostępne w małym komputerze napięcie 3,3 V. Jednak aby sterować zewnętrznymi urządzeniami, które korzystają z wyższego napięcia niż dostępne w Raspberry Pi, niezbędne jest wyjście typu otwarty kolektor (schemat układu, który kryje się pod tym wyjściem został przedstawiony poniżej). &lt;br /&gt;
&lt;br /&gt;
[[Plik:OpenCollector.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat układu z wyjściem typu otwarty kolektor. Składa się z tranzystorów, oporników i diod. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Takich układów otwartego kolektora na desce Gertboard jest 6 (od RLY1 do RLY6), znajdują się one w obszarze oznaczonym żółtą ramką i każdy z nich działa przy napięciach do 50 V i prądach do 500 mA.&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Zasadniczo rola tego obwodu sprowadza się do kontroli połączenia uziemienia zewnętrznego obwodu elektrycznego z uziemieniem deski Gertboard, co pozwala na &amp;quot;zamknięcie&amp;quot; obwodu i popłynięcie prądu. Wyjście może przyjmować dwa stany:&lt;br /&gt;
* wysokiej impedancji (jakby do niczego nie było podłączone)&lt;br /&gt;
* zwarcia z masą (obwód jest &amp;quot;zamknięty&amp;quot; i płynie przez niego prąd)&lt;br /&gt;
&lt;br /&gt;
Zatem aby móc decydować o włączeniu/wyłączeniu zewnętrznego urządzenia należy podłączyć dodatni biegun zasilania zewnętrznego do wejścia 'common' (czyli RPWR na desce Gertboard), ujemny biegun zasilania zewnętrznego do uziemienia deski, oraz koniec obwodu do wyjścia 'out' (np. RLY1). W ten sposób, gdy połączymy również wyjście z Raspberry np. GP4 z portem RLY1 ('Raspi'), będziemy mogli za pomocą sygnału z Raspberry decydować o tym czy przez zewnętrzny układ popłynie prąd. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przykładowego wyjścia typu otwarty kolektor, studenci mają za zadanie odtworzyć połączenia przedstawione na poniższym schemacie oraz zbudować zewnętrzny obwód składający się z dwóch diod (czerwonej, zielonej), opornika (o oporze 0,6 k&amp;amp;Omega;) i źródła zasilania (bateria 9V). Następnie należy zapoznać się z implementacją programu sterującego zasilaniem diod.&lt;br /&gt;
 &lt;br /&gt;
[[Plik:open_collector.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu wyjścia typu otwarty kolektor. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
chan_num = 6                                        # available channel number&lt;br /&gt;
channel = 0                                         # set channel to 0 initially so &lt;br /&gt;
                                                    # it will ask for user input&lt;br /&gt;
def which_channel():&lt;br /&gt;
    print &amp;quot;Which driver do you want to test?&amp;quot;&lt;br /&gt;
    chan = raw_input(&amp;quot;Type a number between 1 and %d\n&amp;quot; % chan_num)      # User inputs channel number&lt;br /&gt;
    while not chan.isdigit():                                            # Check valid user input                        &lt;br /&gt;
        chan = raw_input(&amp;quot;Try again-just numbers 1-%d !\n&amp;quot; % chan_num)   # Make them do it again if wrong   &lt;br /&gt;
    return chan&lt;br /&gt;
&lt;br /&gt;
while not 0 &amp;lt; chan &amp;lt; (chan_num + 1):                # ask for a channel number&lt;br /&gt;
    chan = int(which_channel())                     # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the open collector test:&amp;quot;&lt;br /&gt;
print &amp;quot;GP4 in J2 --- RLY%d in J4&amp;quot; % channel&lt;br /&gt;
print &amp;quot;+ of external power source --- RPWR in J6&amp;quot;&lt;br /&gt;
print &amp;quot;ground of external power source --- GND (any)&amp;quot;&lt;br /&gt;
print &amp;quot;ground side of your circuit --- RLY%d in J%d&amp;quot; % (channel, channel+11)&lt;br /&gt;
print &amp;quot;+ of your circuit --- RPWR (any)&amp;quot;&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)                              # initialise RPi.GPIO&lt;br /&gt;
GPIO.setup(4, GPIO.OUT)                             # set up port 4 for output&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    for i in range(10):                             # do this 10 times&lt;br /&gt;
        GPIO.output(4, 1)                           # switch port 4 on&lt;br /&gt;
        sleep(0.4)                                  # wait 0.4 seconds&lt;br /&gt;
        GPIO.output(4, 0)                           # switch port 4 off&lt;br /&gt;
        sleep(0.4)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:                           # trap a CTRL+C keyboard interrupt&lt;br /&gt;
    GPIO.cleanup()                                  # resets all GPIO ports&lt;br /&gt;
&lt;br /&gt;
GPIO.cleanup()                                      # on finishing,reset all GPIO ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po wykonaniu zadania testowego należy zmodyfikować program sterujący i okablowanie tak, aby diody zapalały się 10-cio krotnie na 2 sekundy z przerwą trwającą 1 sekundę oraz sterowanie odbywało się przez wyjście RLY3.&lt;br /&gt;
&lt;br /&gt;
== Sterownik silnika prądu stałego ==&lt;br /&gt;
&lt;br /&gt;
Sterownik silnika prądu stałego wbudowany w deskę Gertboard może przyjąć maksymalne napięcie 18 V i natężenie 2A. Wymaga on dwóch logicznych sygnałów wejściowych A i B (na desce są one oznaczone MOTOA i MOTOB). Zachowanie silnika w zależności od stanu logicznego sygnałów A i B zostało zobrazowane w tabeli poniżej.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor_tabela.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tabela przedstawiająca zachowanie silnika w zależności od stanu logicznego wejść A i B. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
O typie ruchu silnika (lub jego braku) decyduje stan logiczny sygnałów. Natomiast gdy chcemy kontrolować jego prędkość musimy kontrolować stosunek pojawiania się 1 i 0 w sygnale. W tym celu stosuje się modulację szerokości impulsów. Przykładowe sygnały logiczne z zastosowaną modulacją szerokości impulsów zostały zaprezentowane na obrazku poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:motoAB.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przykłady sygnału logicznego na wejściu A. Górny wykres przedstawia sytuację gdy silniczek kręci się dwa razy szybciej niż w sytuacji przedstawionej na dolnym wykresie. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Znając podstawy sterowania silniczkiem można przejść do wykonywania połączeń, których schemat został przedstawiony poniżej. Docelowo chcemy aby wysłany przez Raspberry sygnał logiczny z portu GP18 był sygnałem MOTOA, natomiast sygnał z portu GP17 był przekazany dalej jako MOTOB. Po wykonaniu połączeń należy zapoznać się ze sterującym programem komputerowym i uruchomić go.&lt;br /&gt;
&lt;br /&gt;
[[Plik:motor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączenia do testu silniczka. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
ports = [18,17]             # define which ports to be pulsed (using a list)&lt;br /&gt;
Reps = 400                  # 2000 Hz cycle time, so Reps=400 is 0.2s for each percentage ON&lt;br /&gt;
Hertz = 2000                # Cycle time. You can tweak this, Max 3000               &lt;br /&gt;
Freq = (1 / float(Hertz)) - 0.0003           # run_motor loop code takes 0.0003s&lt;br /&gt;
&lt;br /&gt;
for port_num in ports:                       # set the ports up for output&lt;br /&gt;
    GPIO.setup(port_num, GPIO.OUT)           # set up GPIO output channel&lt;br /&gt;
    print (&amp;quot;setting up GPIO port:&amp;quot;, port_num)&lt;br /&gt;
    GPIO.output(port_num, False)             # set both ports to OFF&lt;br /&gt;
    &lt;br /&gt;
def run_motor(Reps, pulse_width, port_num, time_period):&lt;br /&gt;
    try:                                     # try: except:, traps errors&lt;br /&gt;
        for i in range(0, Reps):&lt;br /&gt;
            GPIO.output(port_num, True)      # switch port on&lt;br /&gt;
            sleep(pulse_width)               # make sure pulse stays on for correct time&lt;br /&gt;
            GPIO.output(port_num, False)     # switch port off&lt;br /&gt;
            sleep(time_period)               # time_period for port OFF defined in run_loop&lt;br /&gt;
    except KeyboardInterrupt:                # reset all ports used by this program if CTRL-C pressed&lt;br /&gt;
        GPIO.cleanup()&lt;br /&gt;
&lt;br /&gt;
def run_loop(startloop, endloop, step, port_num, printchar):&lt;br /&gt;
    for pulse_width_percent in range(startloop, endloop, step):&lt;br /&gt;
        print (printchar, sep='', end='')&lt;br /&gt;
        sys.stdout.flush()&lt;br /&gt;
        pulse_width = pulse_width_percent / float(100) * Freq           # define exact pulse width&lt;br /&gt;
        time_period = Freq - (Freq * pulse_width_percent / float(100))  # sleep period needed to get required Hz&lt;br /&gt;
        run_motor(Reps, pulse_width, port_num, time_period)&lt;br /&gt;
    print(&amp;quot;&amp;quot;)                                                           # print line break between runs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;\nThese are the connections for the Gertboard motor test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP17 in J2 --- MOTB (just above GP1)&amp;quot;)&lt;br /&gt;
print (&amp;quot;GP18 in J2 --- MOTA (just above GP4)&amp;quot;)&lt;br /&gt;
print (&amp;quot;+ of external power source --- MOT+ in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;ground of external power source --- GND (any)&amp;quot;)&lt;br /&gt;
print (&amp;quot;one wire for your motor in MOTA in J19&amp;quot;)&lt;br /&gt;
print (&amp;quot;the other wire for your motor in MOTB in J19&amp;quot;)&lt;br /&gt;
command = raw_input(&amp;quot;When ready hit enter.\n&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 18,'+')      # (startloop, endloop, step, port_num, printchar, loopnum)&lt;br /&gt;
run_loop(95, 5, -1, 18,'-')     # if you go all the way to 100% it seems out of control at the changeover&lt;br /&gt;
sleep(0.2)                      # a slight pause before change direction stops sudden motor jerking&lt;br /&gt;
print (&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, sep='', end='')&lt;br /&gt;
run_loop(5, 95, 1, 17,'+')&lt;br /&gt;
run_loop(95, 5, -1, 17,'-')&lt;br /&gt;
&lt;br /&gt;
GPIO.output(port_num, False)            # Finish up: set both ports to off&lt;br /&gt;
GPIO.cleanup()                          # reset all ports used by this program&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie student ma za zadanie tak zmodyfikować program aby wykonywał:&lt;br /&gt;
*obrót silniczka o około 180 stopni w prawo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
*obrót silniczka o około 180 stopni w lewo&lt;br /&gt;
*przerwa trwająca 1 sekundę&lt;br /&gt;
*powtórzenie poprzednich 2 podpunktów 5 razy&lt;br /&gt;
&lt;br /&gt;
== Komunikacja przez SPI ==&lt;br /&gt;
&lt;br /&gt;
SPI (ang. &amp;quot;Serial Peripheral Interface&amp;quot;) to szeregowy interfejs urządzeń peryferyjnych, pozwalający na komunikację głównego mikroprocesora (ang. &amp;quot;Master&amp;quot;) z przetwornikiem analogowo-cyfrowym i cyfrowo-analogowym (lub innym urządzeniem peryferyjnym, ang. &amp;quot;Slave&amp;quot;). Składa się on z 3 linii komunikacyjnych działających równocześnie:&lt;br /&gt;
*SCLK (ang. &amp;quot;Serial CLocK&amp;quot;) - sygnał zegarowy/taktujący przesyłany od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MOSI (ang. &amp;quot;Master Output Slave Input&amp;quot;) - sygnał od &amp;quot;Master&amp;quot; do &amp;quot;Slave&amp;quot;&lt;br /&gt;
*MISO (ang. &amp;quot;Master Input Slave Output&amp;quot;) - sygnał od &amp;quot;Slave&amp;quot; do &amp;quot;Master&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Plik:gertboard2.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Płytka Gertboard z zaznaczonymi obszarami funkcyjnymi. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
Przetworniki wbudowane w deskę Gertboard znajdują się w obszarze zaznaczonym pomarańczową ramką. Jak widać każdy z przetworników ma dostępne po dwa kanały: analogowo-cyfrowy AD0, AD1 oraz cyfrowo-analogowy DA0, DA1. Wyboru używanego przetwornika dokonuje się poprzez nadanie logicznej wartości 0 na jednym z portów: CSnA w przypadku przetwornika analogowo-cyfrowego, lub CSnB w przypadku przetwornika cyfrowo-analogowego. &lt;br /&gt;
&lt;br /&gt;
=== Przetwornik cyfrowo-analogowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik cyfrowo-analogowy wbudowany w deskę Gertboard jest 8-bitowy, z maksymalnym napięciem 2,04 V. Napięcie wytworzone na wyjściu (pin DA0 lub DA1) &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; opisane jest wzorem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;V_{out}=\frac{D_{in}}{256} \cdot {2,048 V}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; to liczba 8-bitowa z zakresu od 0 do 256, którą użytkownik może dowolnie wybrać w zależności od oczekiwanego rezultatu (napięcia na wyjściu). Ta liczba, wraz z innymi niezbędnymi informacjami, musi zostać przekazana do przetwornika poprzez protokół SPI w postaci 2 bajtów (2 liczb 8-bajtowych) czyli 16 bitów:&lt;br /&gt;
*16-13 bit: różne informacje:&lt;br /&gt;
**16: numer kanału (0 lub 1)&lt;br /&gt;
**15: bez znaczenia (0)&lt;br /&gt;
**14: ''gain'' (mnożnik razy dwa - 0 lub mnożnik razy jeden - 1)&lt;br /&gt;
**13: ''shutdown mode'' (off-0, on-1 dla oszczędności energii)&lt;br /&gt;
*12-5 bit: liczba &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt; &lt;br /&gt;
*4-1 bit: nieznaczące zera&lt;br /&gt;
&lt;br /&gt;
Zatem, chcąc uzyskać na wyjściu przykładowe napięcie &amp;lt;math&amp;gt;V_{out}&amp;lt;/math&amp;gt; 1,5 V najpierw z powyższego wzoru obliczamy liczbę &amp;lt;math&amp;gt;D_{in}&amp;lt;/math&amp;gt;, która wyniesie 188. Następnie zawieramy informacje w poszczególnych bitach:&lt;br /&gt;
*16-13 bit: kanał zerowy-0, bez znaczenia-0, ''gain''-1, ''shutdown mode''-1  ; 0011&lt;br /&gt;
*12-5 bit: liczba 188 to 10111100&lt;br /&gt;
*4-1 bit: 0000&lt;br /&gt;
których ciąg: 0011101111000000 tworzy dwie liczby 8-bitowe: 00111011 (liczba 59) 11000000 (liczba 192). Te dwie liczby podajemy przy użyciu komunikacji SPI. &lt;br /&gt;
&lt;br /&gt;
Aby zapoznać się z działaniem przetwornika DA studenci mają za zadanie wykonać połączenia przedstawione na poniższym schemacie oraz zapoznać się z przykładowym programem. Do mierzenia wygenerowanego napięcia należy skorzystać z uniwersalnego multimetru. &lt;br /&gt;
&lt;br /&gt;
[[Plik:dtoa.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika DA. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import spidev&lt;br /&gt;
import subprocess&lt;br /&gt;
from time import sleep&lt;br /&gt;
&lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,1)                                   # The Gertboard DAC is on SPI channel 1 (GPIO7)&lt;br /&gt;
                                                # ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
channel = 3                                     # set initial random value to force user selection&lt;br /&gt;
voltages = [0.0,0.5,1.02,1.36,2.04]             # voltages for display&lt;br /&gt;
common = [0,0,0,160,240]                        # 2nd byte common to both channels&lt;br /&gt;
                                                &lt;br /&gt;
while not (channel == 1 or channel == 0):       # channel is set by user input&lt;br /&gt;
    channel = int(which_channel())              # continue asking until answer 0 or 1 given&lt;br /&gt;
if channel == 1:                                &lt;br /&gt;
    num_list = [176,180,184,186,191]            # 1st byte list (channel-dependent)&lt;br /&gt;
else:&lt;br /&gt;
    num_list = [48,52,56,58,63]                 # 1st byte list (channel-dependent)&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;These are the connections for the digital to analogue test:&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP11 to SCLK&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP10 to MOSI&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP9 to MISO&amp;quot;&lt;br /&gt;
print &amp;quot;jumper connecting GP7 to CSnB&amp;quot;&lt;br /&gt;
print &amp;quot;Multimeter connections (set your meter to read V DC):&amp;quot;&lt;br /&gt;
print &amp;quot;  connect black probe to GND&amp;quot;&lt;br /&gt;
print &amp;quot;  connect red probe to DA%d on J29&amp;quot; % channel&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for i in range(5):&lt;br /&gt;
    r = spi.xfer2([num_list[i],common[i]])                   #send 1st and 2nd byte through SPI&lt;br /&gt;
    print &amp;quot;Your multimeter should read about %.2fV&amp;quot; % voltages[i]   &lt;br /&gt;
    raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
r = spi.xfer2([16,0])  # clear channel 0 -&amp;gt; set 0 V -&amp;gt; 1st byte 00010000 [16], 2nd byte 00000000 [0]&lt;br /&gt;
r = spi.xfer2([144,0]) # clear channel 1 -&amp;gt; set 0 V -&amp;gt; 1st byte 10010000 [144], 2nd byte 00000000 [0]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Następnie studenci mają za zadanie tak zmodyfikować program aby uzyskać na wyjściu napięcia: 0,44 V, 0,88 V, 1,22 V.&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy ===&lt;br /&gt;
&lt;br /&gt;
Przetwornik analogowo-cyfrowy wbudowany w deskę Gertboard jest 10-bitowy, z częstością próbkowania 72kHz. Przetwornik zwraca przez SPI 3 bajty danych [XXXX XXXX][XXXX DDDD][DDDD DDXX]. Bity od 12 do 3 tworzą 10-cio bitową liczbę z zakresu 0-1023, co odpowiada wartościom napięcia z zakresu 0-3.3 V. &lt;br /&gt;
&lt;br /&gt;
Jednak aby odebrać te dane należy również wysłać do przetwornika informację o tym, z którego kanału sygnał nas interesuje. Do tego celu służy jedna funkcja ''spi.xfer2'', która przesyła informacje do (argument funkcji) i z (wartość zwrócona przez funkcję) przetwornika. Aby odczytać sygnał z kanału 0 należy nadać 3 bajty: [0000 0001] [1000 0000] [0000 0000] (czyli liczby: 1,128,0), natomiast aby odczytać sygnał z kanału 1 należy nadać 3 bajty: [0000 0001] [1100 0000] [0000 0000] (czyli liczby: 1,192,0).&lt;br /&gt;
&lt;br /&gt;
Zadanie testowe będzie wymagało wykorzystania źródła zmiennego sygnału analogowego. W tym celu użyty zostanie potencjometr - regulowany dzielnik napięcia. Napięcie wyjściowe &amp;lt;math&amp;gt;U_{wy}&amp;lt;/math&amp;gt; na potencjometrze opisuje równanie:&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;U_{wy} = \frac{U_{we}}{R+R_1} \cdot R_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
gdzie &amp;lt;math&amp;gt;U_{we}&amp;lt;/math&amp;gt; to napięcie wejściowe, R to stały opór potencjometru, natomiast &amp;lt;math&amp;gt;R_{1}&amp;lt;/math&amp;gt; to zmienny opór (regulowany pokrętłem). &lt;br /&gt;
&lt;br /&gt;
W zadaniu testowym podłączamy jedną nóżkę potencjometru do zasilania z Raspbery (3,3 V), drugą do uziemienia, a trzecią jako wejście analogowe do przetwornika analogowo-cyfrowego na kanale AD0. Wykonujemy resztę połączeń niezbędnych do komunikacji przy użyciu SPI. Następnie, należy zapoznać się z programem zamieszczonym poniżej i uruchomić go. &lt;br /&gt;
&lt;br /&gt;
[[Plik:atod.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w teście przetwornika AD. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
from __future__ import print_function       &lt;br /&gt;
from time import sleep&lt;br /&gt;
import subprocess&lt;br /&gt;
import spidev&lt;br /&gt;
import sys&lt;br /&gt;
                   &lt;br /&gt;
def which_channel():&lt;br /&gt;
    channel = raw_input(&amp;quot;Which channel do you want to test? Type 0 or 1.\n&amp;quot;)  # User inputs channel number&lt;br /&gt;
    while not channel.isdigit():                                              # Check valid user input&lt;br /&gt;
        channel = raw_input(&amp;quot;Try again - just numbers 0 or 1 please!\n&amp;quot;)      # Make them do it again if wrong&lt;br /&gt;
    return channel&lt;br /&gt;
&lt;br /&gt;
def get_adc(channel):                                   # read SPI data from MCP3002 chip&lt;br /&gt;
    if ((channel &amp;gt; 1) or (channel &amp;lt; 0)):                # Only 2 channels 0 and 1 else return -1&lt;br /&gt;
        return -1&lt;br /&gt;
    r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])                 # these two lines are explained in more detail at the bottom&lt;br /&gt;
    ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
    return ret &lt;br /&gt;
&lt;br /&gt;
def display(char, reps, adc_value, spaces):             # function handles the display of ##### &lt;br /&gt;
    print ('\r',&amp;quot;{0:04d}&amp;quot;.format(adc_value), ' ', char * reps, ' ' * spaces,'\r', sep='', end='') &lt;br /&gt;
    sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# reload spi drivers to prevent spi failures&lt;br /&gt;
unload_spi = subprocess.Popen('sudo rmmod spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
start_spi = subprocess.Popen('sudo modprobe spi_bcm2708', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
sleep(3)   &lt;br /&gt;
&lt;br /&gt;
channel = 3                # set channel to 3 initially so it will ask for user input (must be 0 or 1)&lt;br /&gt;
while not (channel == 1 or channel == 0):       # continue asking until answer 0 or 1 given&lt;br /&gt;
    channel = int(which_channel())              # once proper answer given, carry on&lt;br /&gt;
&lt;br /&gt;
print (&amp;quot;These are the connections for the analogue to digital test:&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP11 to SCLK&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP10 to MOSI&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP9 to MISO&amp;quot;)&lt;br /&gt;
print (&amp;quot;jumper connecting GP8 to CSnA&amp;quot;)&lt;br /&gt;
print (&amp;quot;Potentiometer connections:&amp;quot;)&lt;br /&gt;
print (&amp;quot;  (call 1 and 3 the ends of the resistor and 2 the wiper)&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 3 to 3V3&amp;quot;)&lt;br /&gt;
print (&amp;quot;  connect 2 to AD%d&amp;quot; % channel);&lt;br /&gt;
print (&amp;quot;  connect 1 to GND&amp;quot;)&lt;br /&gt;
raw_input(&amp;quot;When ready hit enter.\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
spi = spidev.SpiDev()&lt;br /&gt;
spi.open(0,0)                                   # The Gertboard ADC is on SPI channel 0 (GPIO8)&lt;br /&gt;
&lt;br /&gt;
char = '#'                                      # define the bar chart character&lt;br /&gt;
iterations = 0                                  # initial value for iteration counter&lt;br /&gt;
while iterations &amp;lt; 600:&lt;br /&gt;
    adc_value = (get_adc(channel))&lt;br /&gt;
    reps = adc_value / 16&lt;br /&gt;
    spaces = 64 - reps&lt;br /&gt;
    display(char, reps, adc_value, spaces)&lt;br /&gt;
    sleep(0.05)                                 # need a delay so people using ssh don't get slow response&lt;br /&gt;
    iterations += 1                             # limits length of program running to 30s [600 * 0.05]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# r = spi.xfer2([1,(2+channel)&amp;lt;&amp;lt;6,0])&lt;br /&gt;
# x &amp;lt;&amp;lt; 6 (it returns x with the bits shifted to the right by 6 places)&lt;br /&gt;
# Send 3 bytes: [sgl/diff] [odd/sign] [MSBF]&lt;br /&gt;
# sgl/diff = 1; odd/sign = channel; MSBF = 0  &lt;br /&gt;
# channel = 0 sends [0000 0001] [1000 0000] [0000 0000]&lt;br /&gt;
# channel = 1 sends [0000 0001] [1100 0000] [0000 0000]&lt;br /&gt;
&lt;br /&gt;
# EXPLANATION of &lt;br /&gt;
# ret = ((r[1]&amp;amp;15) &amp;lt;&amp;lt; 6) + (r[2] &amp;gt;&amp;gt; 2)&lt;br /&gt;
# spi.xfer2 returns three 8-bit bytes. We must then parse out the correct &lt;br /&gt;
# 10-bit byte from the 24 bits returned. The following line discards all bits but&lt;br /&gt;
# the 10 data bits from the center of the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Przetwornik analogowo-cyfrowy + Silnik ===&lt;br /&gt;
&lt;br /&gt;
Zadanie to łączy w sobie wiedzę na temat przetwornika analogowo-cyfrowego i sterownika silnika prądu stałego. Sygnał analogowy pochodzący z potencjometru ma zostać odczytany przez Raspberry Pi, a następnie zamieniony na sygnał logiczny o odpowiedniej szerokości impulsów będący wejściem do sterownika silnika. W ten sposób, kontrolując wskazania potencjometru (za pomocą śrubokrętu) można jednocześnie sterować prędkością i kierunkiem obrotów silnika. Docelowo chcemy, aby maksymalne napięcie na potencjometrze odpowiadało maksymalnej prędkości w jednym kierunku, zerowe napięcie maksymalnej prędkości w drugim kierunku, natomiast środkowe napięcie braku ruchu silniczka. Poniżej zamieszczono schemat połączeń niezbędnych do tego zadania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:moto_pot.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń w zadaniu z przetwornikiem AD i silnikiem. Źródło: Gertboard User Maual]]&lt;br /&gt;
&lt;br /&gt;
== Tranzystor ==&lt;br /&gt;
&lt;br /&gt;
Tranzystor to element elektroniczny, który wzmacnia sygnał elektryczny dzięki specyficznej budowie złącz trzech elektrod półprzewodnikowych: emiter, baza, kolektor. Stosunkowo niewielki prąd płynący pomiędzy bazą i emiterem może sterować większym prądem płynącym między kolektorem i emiterem. Na zajęciach korzystać będziemy z tranzystora typu npn. &lt;br /&gt;
&lt;br /&gt;
[[Plik:tranzystor.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Tranzystor npn 2N2222a. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Cechą charakterystyczną każdego tranzystora jest współczynnik wzmocnienia prądu (dla naszych tranzystorów &amp;amp;beta;=100), który jednak zależy (dość silnie) od temperatury. Głównym celem tego zadania jest zbadanie charakterystyki tranzystora - zależności prądu na bazie i kolektorze: &amp;lt;math&amp;gt;I_{K} = \beta \cdot I_{B} &amp;lt;/math&amp;gt;. Pozwoli nam ona na wyznaczenie współczynnika wzmocnienia (współczynnik kierunkowy prostej) oraz zaobserwowanie zmian zachodzących wraz z ogrzewaniem tranzystora. &lt;br /&gt;
&lt;br /&gt;
[[Plik:schemat_tranzystor.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do charakterystyki tranzystora]]&lt;br /&gt;
&lt;br /&gt;
Kolejność procedury jest następująca:&lt;br /&gt;
# za pomocą przetwornika cyfrowo-analogowego podajemy napięcie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; na port DA0 (na bazę tranzystora)&lt;br /&gt;
# znając oporność opornika na bazie &amp;lt;math&amp;gt;R_{B}=22k\Omega&amp;lt;/math&amp;gt;, oraz wiedząc, że pomiędzy bazą a emiterem jest spadek napięcia 0.6  V, możemy policzyć prąd na bazie: &amp;lt;math&amp;gt;I_{B} = \frac{U_{B}-0.6 V}{R_{B}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# za pomocą przetwornika analogowo-cyfrowego odczytujemy napięcie &amp;lt;math&amp;gt;U_{K}&amp;lt;/math&amp;gt; na kolektorze na porcie AD0&lt;br /&gt;
# znając oporność opornika na kolektorze &amp;lt;math&amp;gt;R_{K}=0.6k\Omega&amp;lt;/math&amp;gt;, możemy policzyć prąd na kolektorze: &amp;lt;math&amp;gt;I_{K} = \frac{3.3V -U_{K}}{R_{K}} &amp;lt;/math&amp;gt;&lt;br /&gt;
# powtarzamy punkty 1-4 dla różnych napięć &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; z zakresu 0-2,04 V&lt;br /&gt;
# rysujemy zależność &amp;lt;math&amp;gt;I_{K}&amp;lt;/math&amp;gt; od &amp;lt;math&amp;gt;I_{B}&amp;lt;/math&amp;gt; i wyliczamy współczynnik kierunkowy prostej&lt;br /&gt;
# powtarzamy eksperyment po ogrzaniu tranzystora ciepłem rąk&lt;br /&gt;
&lt;br /&gt;
Warto zauważyć, że zależność prądu na kolektorze od prądu na bazie nie będzie w całym zakresie liniowa. Dla niskich napięć na bazie &amp;lt;math&amp;gt;U_{B}&amp;lt;/math&amp;gt; (poniżej 0.6 V) tranzystor nie przewodzi prądu. Następnie tranzystor pracuje w zakresie liniowym. Natomiast gdy napięcie na bazie (zatem i prąd na bazie) osiągną pewną graniczną wartość, tranzystor będzie nasycony. Oznacza to, że tranzystor może wzmacniać prąd jedynie do pewnej maksymalnej wartości określonej stosunkiem &amp;lt;math&amp;gt;I_{KMAX} = \frac{3.3V}{R_{K}} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Czujnik temperatury i wilgotności powietrza ==&lt;br /&gt;
&lt;br /&gt;
Na zajęciach używać będziemy czujnika temperatury i wilgotności powietrza AM2302/DH22. Jest on zasilany napięciem 3,3-6 V. Zakres pomiarowy wynosi 0-100 % RH oraz -40 °C do +80 °C, gdzie RH to wilgotność względna wyrażana w procentach. Jest to stosunek rzeczywistej wilgoci w powietrzu do maksymalnej jej ilości, którą może utrzymać powietrze w danej temperaturze. Sygnał cyfrowy jest 8-bitowy, rozdzielczość pomiaru temperatury wynosi 0,1 °C, natomiast wilgotności powietrza ± 0,1 % RH. Jednak jego szacowana dokładność to ± 0,5 °C oraz ± 2 % RH. &lt;br /&gt;
&lt;br /&gt;
[[Plik:temp.png|300px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Czujnik temperatury i wilgotności powietrza. Modele DHT11 oraz DHT22. Źródło: https://cdn-learn.adafruit.com/downloads/pdf/dht.pdf]]&lt;br /&gt;
&lt;br /&gt;
Kolejne nóżki czujnika (od lewej do prawej) to:&lt;br /&gt;
*zasilanie&lt;br /&gt;
*sygnał&lt;br /&gt;
*nic&lt;br /&gt;
*uziemienie&lt;br /&gt;
Aby przetestować działanie czujnika, budujemy obwód elektryczny zgodnie ze schematem przedstawionym poniżej (użyty opornik 5k&amp;amp;Omega; ma spełniać funkcję pull-up).&lt;br /&gt;
&lt;br /&gt;
[[Plik:czujnik.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat połączeń do testowania czujnika]]&lt;br /&gt;
&lt;br /&gt;
Podczas pracy z czujnikiem korzystać będziemy z biblioteki stworzonej przez Adafruit. Umożliwia ona komunikację z wbudowanym 8-bitowym mikro-kontrolerem, który wykonuje konwersję analogowo-cyfrową i przesyła dane w odpowiednim formacie. Dzięki temu sygnał wyjściowy z czujnika można przesyłać na dowolny pin GPIO. Aby pobrać odpowiednią bibliotekę należy wykonać następujące komendy:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
$ sudo apt-get install -y build-essential python-dev git &lt;br /&gt;
$ mkdir -p /home/pi/sources  &lt;br /&gt;
$ cd /home/pi/sources  &lt;br /&gt;
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git  &lt;br /&gt;
$ cd Adafruit_Python_DHT  &lt;br /&gt;
$ sudo python setup.py install  &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Po ich wykonaniu w lokalizacji '/home/pi/sources/Adafruit_Python_DHT/examples/' znajduje się przykładowy skrypt testowy 'AdafruitDHT.py', który można uruchomić z dwoma argumentami:&lt;br /&gt;
#typ czujnika: 11 (dla DHT11), 22 (dla DHT22), 2302 (dla naszego AM2302)&lt;br /&gt;
#numer pinu GPIO, na który nadawany jest sygnał: 4&lt;br /&gt;
&lt;br /&gt;
== Hallotron ==&lt;br /&gt;
&lt;br /&gt;
Hallotron to urządzenie elektroniczne półprzewodnikowe wykorzystywane do pomiaru natężenia pola magnetycznego. Nazwa pochodzi od klasycznego efektu Halla, na którym opiera się jego działanie (wystąpienie różnicy potencjałów w przewodniku znajdującym się w polu magnetycznym). Schemat przedstawiający hallotron i oznaczenie jego &amp;quot;nóżek&amp;quot; znajduje się poniżej. &lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Halotron A324 oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Do zasilania hallotronu potrzebne jest napięcie 5V, na wyjściu napięcie waha się w granicach 2.425 - 2.575 V. Jak widać różnice w napięciu wyjściowym (zależnym od natężenia pola magnetycznego) są bardzo małe i aby je zarejestrować potrzebny będzie wzmacniacz różnicowy, który wzmocni jedynie różnicę pomiędzy typowym napięciem hallotronu (2.5 V) a napięciem uzyskanym poprzez zmianę pola magnetycznego (przybliżanie magnesu). Do naszych celów użyjemy wzmacniacza operacyjnego przedstawionego na poniższym rysunku wraz z opisem nóżek wejściowych i wyjściowych. &lt;br /&gt;
&lt;br /&gt;
[[Plik:wzmacniacz3.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wzmacniacz operacyjny LM324N oraz oznaczenie jego &amp;quot;nóżek&amp;quot;. Źródło: dokumentacja techniczna]]&lt;br /&gt;
&lt;br /&gt;
Jako źródło napięcia typowego dla hallotronu użyjemy potencjometru zasilanego napięciem 5 V i ustawionego na 2.5 V. Montując układ przedstawiony na poniższym schemacie, gdzie opór &amp;lt;math&amp;gt;r=1k\Omega&amp;lt;/math&amp;gt; natomiast &amp;lt;math&amp;gt;R=18k\Omega&amp;lt;/math&amp;gt;, uzyskamy wzmocnienie napięcia różnicowego &amp;lt;math&amp;gt;\beta=\frac{R}{r}=18&amp;lt;/math&amp;gt;. Dodatkowo, tuż przed przetwornikiem analogowo-cyfrowym, należy jeszcze zastosować wtórnik emiterowy (tranzystor) wraz z opornikiem &amp;lt;math&amp;gt;R_{2}=1k\Omega&amp;lt;/math&amp;gt;, który pozwoli na wzmocnienie prądu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:halotron2.png|800px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Schemat obwodu i połączeń w teście hallotronu.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Opis bloku tematycznego:&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i ćwiczeń indywidualnych wykonywanych przez studentów. Studenci w czasie zajęć przygotowują prototypowe układy elektroniczne mierzące wybrane wielkości fizyczne, oprogramowują je w języku Python i testują. Przygotowane uprzednio eksperymenty w ramach zajęć terenowych umieszczane są w wybranych miejscach na terenie Wydziału Fizyki w celu przeprowadzenia ciągłych i automatycznych pomiarów. Zebrane dane są następnie analizowane przez studentów w ramach ćwiczeń.&lt;br /&gt;
===Wyposażenie pracowni===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;figure id=&amp;quot;fig:spiny&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;caption&amp;gt;Moduły i elementy elektroniczne dostępne na pracowni Nowych Technologii&amp;lt;/caption&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 90%&amp;quot;&lt;br /&gt;
! L.p.&lt;br /&gt;
! Nazwa&lt;br /&gt;
! Opis&lt;br /&gt;
!Dostępnych sztuk&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Rezystor 22 Om&lt;br /&gt;
| Rezystor węglowy, THT, 22 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Rezystor 1 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 1 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Rezystor 4.7 MOm&lt;br /&gt;
| Rezystor węglowy, THT, 4.7 MOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Rezystor 10 Om&lt;br /&gt;
| Rezystor węglowy, THT, 10 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Rezystor 620 Om&lt;br /&gt;
| Rezystor węglowy, THT, 620 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Rezystor 100 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 100 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Rezystor 2.2 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 2.2 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Rezystor 11 Om&lt;br /&gt;
| Rezystor węglowy, THT, 11 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Rezystor 10 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 10 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Rezystor 47 Om&lt;br /&gt;
| Rezystor węglowy, THT, 47 Om, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Rezystor 22 kOm&lt;br /&gt;
| Rezystor węglowy, THT, 22 kOm, 1/4 W, 5%&lt;br /&gt;
| 100&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| Kondensator 100 nF&lt;br /&gt;
| Kondensator ceramiczny, THT, 100 nF, 50V, 10%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| Kondensator elektrolityczny 470 uF&lt;br /&gt;
| Kondensator elektrolityczny, THT, 470 uF, 16V, 20%&lt;br /&gt;
| 25&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| Stabilizator napięcia 7805&lt;br /&gt;
| Scalony stabilizator napięcia L7805ABV, nieregulowany, 5V, 1.5A, obudowa TO220, THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ&lt;br /&gt;
| Wzmacniacz operacyjny CA3140EZ, 4.5 MHz, 4-36 VDC, 1 kanał, ubudowa DIP8&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| Fotodioda VTP1220FBH&lt;br /&gt;
| Fotodioda na światło widzialne VTP1220FBH, 550 nm, 400-700 nm, montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| Dioda LED zielona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 15 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| Dioda LED czerwona&lt;br /&gt;
| Dioda LED zielona, 3 mm, 8-50 mcd, 60 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| Dioda LED żółta&lt;br /&gt;
| Dioda LED żółta, 3 mm, 20-30 mcd, 40 st., montaż: THT&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| Przetwornik MCP3004&lt;br /&gt;
| Przetwornik analogowo-cyfrowy (ADC), 4 kanały, 10 bit, 200 kcps, 2.7-5.5 V, obudowa DIP14&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| Ładowarka Imax B6AC Dual Power&lt;br /&gt;
| Mikroprocesorowa ładowarka/balancer akumulatorów LiIon/LiPo/LiFe 1-6 cel, NiCd/NiMH 1-15 cel, Pb 2-20V, Maksymalny prąd ładowania 6A&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| Moduł GPS&lt;br /&gt;
| Moduł GPS Adafriut Ultimate D GPS Breakout fw5632 v3 + CR1220&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2600-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| Czujnik gazów&lt;br /&gt;
| Gassensor Figaro TGS2442-B00&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| Czujnik wilgotności i temperatury&lt;br /&gt;
| DHT22&lt;br /&gt;
| 7&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/figure&amp;gt;&lt;br /&gt;
1. Moduły &amp;quot;mod10DOF&amp;quot;&lt;br /&gt;
Moduł 10DOF zawiera czujniki pozwalające mierzyć zmiany dziewięciu stopni swobody plus ciśnienie (L3G4200D, ADXL345, HMC5883L, BMP085):&lt;br /&gt;
&lt;br /&gt;
*trzyosiowy żyroskop L3G4200D&lt;br /&gt;
*trzyosiowy akcelerometr ADXL345&lt;br /&gt;
*trzyosiowy czujnik pola magnetycznego Honeywell HMC5883L (+/-8gauss)&lt;br /&gt;
*czujnik ciśnienia BMP085 (300 - 1100hPa)&lt;br /&gt;
&lt;br /&gt;
Wszystkie elementy pomiarowe komunikują się magistralą I2C (napięcia logiki i zasilania w zakresie 3-5 V)&lt;br /&gt;
&lt;br /&gt;
2. Moduł &amp;quot;mod10DOF_1&amp;quot;&lt;br /&gt;
Moduł jest analogiczny do powyższego z tym, że wykorzystano w nim inne czujniki: żyroskop ITG3205 (±2000°/sec) i akcelerometr BMA180 (+-1g ... +-16g).&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 1===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komputer jednoukładowy SoC, przykłady&lt;br /&gt;
*Dlaczego Raspberry Pi?&lt;br /&gt;
*Architektura ARM, harvardzka vs Von Neumanna&lt;br /&gt;
*Podstawowe elementy komputera RP, schemat elektryczny, zasilanie, bezpieczeństwo użytkowania, BHP pracy, omówienie zestawu dostępnych elementów&lt;br /&gt;
*Pierwsze uruchomienie RP, logowanie, zapoznanie z systemem&lt;br /&gt;
*Porty GPIO, sterowania programowe, elektroniczny „Hello world!” – mrugająca  dioda, sterowanie elementami wykonawczymi&lt;br /&gt;
&lt;br /&gt;
====Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO)====&lt;br /&gt;
&lt;br /&gt;
[[File:Raspberry-Pi-GPIO-pinouts.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Raspberry-Pi-GPIO-pinouts&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis wyprowadzeń ogólnego portu wejścia/wyjścia (GPIO, ang. General Port Input/Output) we wszystkich modelach Raspberry Pi.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Mrugająca dioda, czyli elektroniczne Hello World!====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku Python:&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
import RPi.GPIO as GPIO&lt;br /&gt;
&lt;br /&gt;
GPIO.setmode(GPIO.BCM)&lt;br /&gt;
 &lt;br /&gt;
StepPins = [24,25,8,7]&lt;br /&gt;
 &lt;br /&gt;
for pin in StepPins:&lt;br /&gt;
  print &amp;quot;Setup pins&amp;quot;&lt;br /&gt;
  GPIO.setup(pin,GPIO.OUT)&lt;br /&gt;
  GPIO.output(pin, False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mrugająca dioda w języku C:&lt;br /&gt;
&amp;lt;source lang = 'c'&amp;gt;&lt;br /&gt;
#include &amp;lt;wiringPi.h&amp;gt;&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
  wiringPiSetup () ;&lt;br /&gt;
  pinMode (0, OUTPUT) ;&lt;br /&gt;
  for (;;)&lt;br /&gt;
  {&lt;br /&gt;
    digitalWrite (0, HIGH) ; delay (500) ;&lt;br /&gt;
    digitalWrite (0,  LOW) ; delay (500) ;&lt;br /&gt;
  }&lt;br /&gt;
  return 0 ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zanim uruchomimy program w C musimy go najpierw skompilować linkując również bibliotekę wiringPi:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
gcc -Wall -o blink blink.c -lwiringPi&lt;br /&gt;
sudo ./blink&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Opis_płyty_RP_small.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Opis płyty głównej komputera Raspberry Pi Rev. 2 ver. B. Złącze Display Serial Interface (DSI) służy do podłączenia zewnętrznego wyświetlacza, złącze Camera Serial Interface (CSI) przeznaczona jest do podłączenia zewnętrznej kamery. Złącze JTAG jest złączem programowania/debugowania chipu Broadcom, wykorzystywane podczas produkcji.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Zajęcia 2===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Generator przebiegu prostokątnego&lt;br /&gt;
*Modulacja PWM (dla chętnych)&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala I2C&lt;br /&gt;
*Uruchomienie czujnika ciśnienia BMP085&lt;br /&gt;
&lt;br /&gt;
====Uruchamianie obsługi magistrali I2C====&lt;br /&gt;
UWAGA! Na niektórych komputerach magistrala I2C została już wcześniej uruchomiona. Zanim zacznie się poniższą procedurę warto najpierw przejść do kroku 6 i sprawdzić czy system nie jest już przypadkiem skonfigurowany i gotowy.&lt;br /&gt;
&lt;br /&gt;
Obsługa magistrali I2C jest domyślnie wyłączona w systemie Raspbian. Żeby ją uruchomić należy wykonać następujące kroki:&lt;br /&gt;
&lt;br /&gt;
1. Otworzyć do edycji czarną listę modułów jądra (plik konfiguracyjny narzędzia modprobe) i wykomentować wiersz dotyczący magistrali I2C&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modprobe.d/raspi-blacklist.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli mamy do czynienia z domyślnym plikiem znajdziemy w nim następujące linie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
z których powinniśmy wykomentować linię blacklist i2c-bcm2708:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# blacklist spi and i2c by default (many users don't need them)&lt;br /&gt;
&lt;br /&gt;
blacklist spi-bcm2708&lt;br /&gt;
#blacklist i2c-bcm2708&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Gdy alias modułu I2C został usunięty z czarnej listy możemy dodać go do listy modułów jądra ładowanych przy starcie systemu. Otwieramy do edycji plik modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i dodajemy nową linię &amp;quot;i2c-dev&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# /etc/modules: kernel modules to load at boot time.&lt;br /&gt;
#&lt;br /&gt;
# This file contains the names of kernel modules that should be loaded&lt;br /&gt;
# at boot time, one per line. Lines beginning with &amp;quot;#&amp;quot; are ignored.&lt;br /&gt;
# Parameters can be specified after the module name.&lt;br /&gt;
&lt;br /&gt;
snd-bcm2835&lt;br /&gt;
i2c-dev&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Zanim zrestartujemy system, żeby załadować nowy moduł, warto przedtem doinstalować narzędzia diagnostyczne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install i2c-tools&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i bibliotekę dla języka Python umożliwiającą wykorzystanie magistrali I2C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install python-smbus&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po zainstalowaniu powyższych pakietów konieczne jest jeszcze dodanie użytkownika (domyślnie użytkownika pi) do grupy mającej dostęp do magistrali:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo adduser pi i2c&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Teraz możemy zrestartować komputer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. Po restarcie moduł i2c-dev powinien już działać. Żeby przetestować hardware próbujemy uzyskać dostęp do magistrali I2C i odczytać adresy podłączony urządzeń:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
i2cdetect -y 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie podłączyliśmy żadnych urządzeń dostaniemy prawdopodobnie następujący wynik:&lt;br /&gt;
[[File:I2cdetect-empty.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-empty&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
Urządzenie pojawiające się pod adresem 0x1b to adres przetwornika audio, oznaczenie UU oznacza, że ten adres już jest używany przez sterownik pracujący w trybie jądra.&lt;br /&gt;
&lt;br /&gt;
Jeżeli prawidłowo podłączyliśmy np. moduł DOF zobaczymy dostępne adresy urządzeń podłączonych do I2C:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeżeli nie udało nam się uzyskać listy adresów:&lt;br /&gt;
&lt;br /&gt;
[[File:I2cdetect-wrong.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:I2cdetect-wrong&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
wówczas warto sprawdzić czy magistrala I2C nie jest dostępna pod innym numerem porządkowym (np. próbując z parametrem -y 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Rezystor podciągający (pull up):&lt;br /&gt;
&amp;lt;source lang = 'python'&amp;gt;&lt;br /&gt;
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 3===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala SPI&lt;br /&gt;
*Uruchomienie przetwornika analogowe&lt;br /&gt;
*Pomiar dowolnej wybranej wielkości analogowej (oświetlania, napięcia, wskazań czujników stężeń)&lt;br /&gt;
&lt;br /&gt;
[[File:spi.jpg|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Komunikacja z wykorzystaniem magistrali SPI odbywa się przez wymianę danych zawartych w rejestrach przesuwnych układów Master i Slave.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi_sck.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Synchronizację transmisji zapewnia generowany przez układ Master sygnał zegarowy SCK.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:spi-multislave.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:spi_sck&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Do magistrali SPI może być dołączone wiele układów Slave. W celu wybrania konkretnego układu, z którym ma odbywa się w danym momencie komunikacja, służy linia Chip Select (CS), osobna dla każdego układu Slave.]]&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 4===&lt;br /&gt;
&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
&lt;br /&gt;
*Komunikacja ze światem zewnętrznym – magistrala 1-Wire&lt;br /&gt;
*Pomiar temperatury z wykorzystaniem czujnika DS18B20&lt;br /&gt;
*Synchronizacja wyników ze zdalną bazą danych (Google Docs)&lt;br /&gt;
*Pomiar temperatury i wilgotności czujnikiem DHT22 – wzorowana na 1-Wire&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 5===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Transmisja szeregowa&lt;br /&gt;
*Komunikacja z modułem GPS&lt;br /&gt;
*Parsowanie danych w standardzie NMEA&lt;br /&gt;
&lt;br /&gt;
====Protokół NMEA 0183====&lt;br /&gt;
Protokół komunikacji NMEA 0183 został opracowany przez amerykańską organizację handlową The National Marine Electronics Association (NMEA), zajmującą się rozwijaniem specyfikacji definiujących interfejsy między różnymi elementami morskiej elektroniki nawigacyjnej. Standard NMEA 0183 opisuje format przesyłu danych i standardy elektroniczne pozwalające na komunikację z komputerami i między sobą takich urządzeń jak sonary, żyrokompasy, autopiloty, anemometry i odbiorniki GPS. Z tego powodu większość, o ile nie wszystkie, odbiorniki GPS mają zaimplementowane przekazywanie danych w powyższym formacie.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Od strony sprzętowej NMEA 0183 bazuje na popularnym komputerowym standardzie komunikacji szeregowej RS232, ale precyzyjnie mówiąc nie jest z nimi tożsamy. Szybkość przesyłu danych może być zmieniana, ale każde podłączone urządzenie powinno być w stanie pracować z prędkością 4800 bitów/s. Dane przesyłane są w postaci znaków ASCII, bez znaku parzystości, z jednymi bitem stopu.&lt;br /&gt;
&lt;br /&gt;
====Dekodowanie wiadomości NMEA 0183====&lt;br /&gt;
Dane są zawsze przesyłane w postaci pojedynczych wiadomości składającej się łącznie z maksymalnie 82 znaków (wliczając znaki końca linii i powrotu karetki). Każda wiadomość zaczyna się znakiem dolara '$' i kończy znakami końca linii i powrotu karetki &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt; (ang. Carriage Return, Line Feed; &amp;lt;CR&amp;gt; o kodzie ASCII 13, &amp;lt;LF&amp;gt; o kodzie ASCII 10). Kolejne dane są rozdzielone od siebie przecinkami, dwuznakowa suma kontrolna pojawia się po gwiazdce &amp;quot;*&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Budowa typowej wiadomość NMEA wygląda następująco:&lt;br /&gt;
&lt;br /&gt;
$GPGGA,193734.000,5214.0928,N,02105.8908,E,2,07,0.98,84.1,M,38.9,M,0000,0000*53&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$ - znak początku wiadomości&lt;br /&gt;
GP - dwuliterowy skrót oznaczający typ urządzenia nadającego dana, GP oznacza dane z odbiornika GPS&lt;br /&gt;
GGA - trzyliterowe oznaczeni rodzaju wiadomości, GGA to kluczowe informacje na temat położenia w trzech wymiarach i dokładności przekazywanych danych&lt;br /&gt;
193734.000 - godzina czasu Greenwich (UTC), w tym przypadku 19:37 i 34 sekundy&lt;br /&gt;
5214.0928 - szerokość geograficzna, pierwsze dwa znaki to liczba stopni, pozostałe liczba minut, czyli: 52'14.0928&amp;quot;&lt;br /&gt;
N - wskaźnik półkuli dla szerokości geogr. półkula północna&lt;br /&gt;
02105.8908 - wysokość geograficzna, pierwsze trzy znaki to liczba stopni, pozostałe liczba minut, czyli: 21'5.8908&amp;quot;&lt;br /&gt;
E - wskaźnik półkuli dla wysokości geogr. półkula wschodnia&lt;br /&gt;
2 - jakość &amp;quot;fixu&amp;quot;: 0 = invalid&lt;br /&gt;
                               1 = GPS fix (SPS)&lt;br /&gt;
                               2 = DGPS fix&lt;br /&gt;
                               3 = PPS fix&lt;br /&gt;
			       4 = Real Time Kinematic&lt;br /&gt;
			       5 = Float RTK&lt;br /&gt;
                               6 = estimated (dead reckoning) (2.3 feature)&lt;br /&gt;
			       7 = Manual input mode&lt;br /&gt;
			       8 = Simulation mode&lt;br /&gt;
07 - liczba śledzonych satelitów&lt;br /&gt;
0.98 - horyzontalne rozmycie położenia&lt;br /&gt;
84.1,M - wysokość w metrach nad średnim poziomem morza&lt;br /&gt;
38.9,M - wysokość geoidy w metrach (średniego poziomu morza) ponad elipsoidę WGS84 (zbiór parametrów określających wielkość i kształt Ziemi oraz właściwości jej potencjału grawitacyjnego. System ten definiuje elipsoidę, która jest generalizacją kształtu geoidy, wykorzystywaną do tworzenia map)&lt;br /&gt;
0000 - czas w sekundach od ostatniej aktualizacji DGPS&lt;br /&gt;
0000 - numer identyfikacyjny stacji DGPS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dostępne na pracowni moduły GPS są w stanie generować następujące komunikaty: GSA (Overall Satellite data), GSV (Detailed Satellite dat), RMC (recommended minimum data for gps), VTG (Vector track an Speed over the Ground), GGA (Fix information), &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Poniżej znajduje się fragment sekwencji wiadomości wysyłanych przez odbiornik GPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
$GPRMC,193749.000,A,5214.1444,N,02105.8814,E,24.61,15.81,050215,,,D*61&lt;br /&gt;
$GPVTG,15.81,T,,M,24.61,N,45.60,K,D*03&lt;br /&gt;
$GPGGA,193750.000,5214.1511,N,02105.8847,E,2,07,0.99,81.6,M,38.9,M,0000,0000*5F&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.79,0.99,1.49*02&lt;br /&gt;
$GPRMC,193750.000,A,5214.1511,N,02105.8847,E,25.39,17.50,050215,,,D*6C&lt;br /&gt;
$GPVTG,17.50,T,,M,25.39,N,47.04,K,D*01&lt;br /&gt;
$GPGGA,193751.000,5214.1579,N,02105.8884,E,2,07,0.98,81.4,M,38.9,M,0000,0000*5C&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193751.000,A,5214.1579,N,02105.8884,E,26.33,18.90,050215,,,D*66&lt;br /&gt;
$GPVTG,18.90,T,,M,26.33,N,48.79,K,D*0E&lt;br /&gt;
$GPGGA,193752.000,5214.1649,N,02105.8925,E,2,07,0.98,81.2,M,38.9,M,0000,0000*53&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPRMC,193752.000,A,5214.1649,N,02105.8925,E,26.79,20.03,050215,,,D*60&lt;br /&gt;
$GPVTG,20.03,T,,M,26.79,N,49.63,K,D*0B&lt;br /&gt;
$GPGGA,193753.000,5214.1720,N,02105.8966,E,2,07,0.99,81.2,M,38.9,M,0000,0000*5A&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.99,1.49*03&lt;br /&gt;
$GPRMC,193753.000,A,5214.1720,N,02105.8966,E,27.30,19.66,050215,,,D*6D&lt;br /&gt;
$GPVTG,19.66,T,,M,27.30,N,50.58,K,D*0E&lt;br /&gt;
$GPGGA,193754.000,5214.1791,N,02105.9011,E,2,07,0.98,81.1,M,38.9,M,0000,0000*5D&lt;br /&gt;
$GPGSA,A,3,12,17,14,24,06,15,25,,,,,,1.78,0.98,1.49*02&lt;br /&gt;
$GPGSV,2,1,08,24,81,195,46,12,61,265,46,17,30,050,40,14,23,317,32*71&lt;br /&gt;
$GPGSV,2,2,08,06,22,103,39,25,21,261,26,33,21,223,26,15,17,197,21*70&lt;br /&gt;
$GPRMC,193754.000,A,5214.1791,N,02105.9011,E,27.27,23.10,050215,,,D*66&lt;br /&gt;
$GPVTG,23.10,T,,M,27.27,N,50.54,K,D*0C&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W przypadku braku danych wysyłane są puste pola rozdzielone przecinkami - brak &amp;quot;fixu&amp;quot; GPS nie zatrzymuje transmisji!&lt;br /&gt;
&lt;br /&gt;
====Konfiguracja układu UART w Raspbian====&lt;br /&gt;
Port szeregowy w Raspberry Pi domyślnie jest skonfigurowany do celu debugowania a także na jego wyjście przekierowane wszystkim komunikaty startowe. Ponadto, na port szeregowy jest przekierowany jeden ze standardowych terminali umożliwiający podanie nazwy użytkownika, hasła i zalogowanie się do komputera. Domyślnie port szeregowy w Raspbian jest dostępny jak /dev/ttyAMA0. Żeby przejąć nad nim pełną kontrolę nad należy domyślną konfigurację zmodyfikować, tak aby mógł być wykorzystany wyłącznie do naszych celów i żeby jego praca nie była zakłócana niepotrzebnymi komunikatami.&lt;br /&gt;
&lt;br /&gt;
1. Po pierwsze otwieramy do edycji plik /boot/cmdline.txt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /boot/cmdline.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinny się w nim znajdować mniej więcej następujące ustawienia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Słowo kluczowe console ustawia standardowy strumień wyjścia na port szeregowy (ttyAMA0) i trafią tam wszystkie komunikaty pojawiające się w trakcie bootowania systemu, natomiast słowo kluczowe kgdboc włącza tryb debugowania jądra. Żeby uwolnić port szeregowy od tych zastosowań musimy usunąć wszystkie odniesienia do ttyAMA0, modyfikując powyższy wiersz np. do następującej postaci:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Teraz pozostaje zmodyfikować ustawienia terminali:&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik /etc/inittab:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/inittab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gdzie znajdujemy następujący fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i go wykomentowujemy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#Spawn a getty on Raspberry Pi serial line&lt;br /&gt;
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Żeby zmiany weszły w życie musimy jeszcze zrestartować system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo reboot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Po restarcie powinniśmy dysponować w zasadzie standardowym linuksowym portem szeregowym, niezakłócanym przez żadne procesy systemowe. Poprawność powyższej procedury możemy sprawdzić upewniając się jaka jest aktualna konsola ustawiona dla jądra:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cat /proc/cmdline&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i czy żaden proces nie używa portu szeregowego (w szczególności getty):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
ps aux | grep ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Narzędzia do testowania modułu GPS====&lt;br /&gt;
&lt;br /&gt;
Żeby przetestować czy nasz moduł GPS funkcjonuje prawidłowo instalujemy następujące narzędzia:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
sudo apt-get install minicom&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po pierwsze możemy podejrzeć czy nasz moduł GPS wysyła cokolwiek przez port szeregowy. Używamy do tego narzędzia minicom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
minicom -b 9600 -o -D /dev/ttyAMA0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Żeby z niego wyjść należy wcisnąć 'Ctr+A' a następnie 'X' i potwierdzić wybór.&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć komunikaty NMEA, nawet jeżeli odbiornik jest uruchomiony w budynku :&lt;br /&gt;
&lt;br /&gt;
[[File:Minicom.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:minicom&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
W zależności czy moduł już &amp;quot;zafixował&amp;quot; położenie, czy jeszcze nie, zobaczymy więcej lub mniej aktualnych danych. Należy pamiętać, że nawet przy dobrej widoczności satelitów potrzeba minimum około 45 sekund na uzyskanie &amp;quot;fixu&amp;quot;. Jeżeli otrzymujemy dane, możemy spróbować użyć gotowego programu do ich parsowania. W tym celu uruchamiamy demon parsujący dane z portu szeregowego:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Następnie uruchamiam program do wyświetlania danych:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
cgps -s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Powinniśmy zobaczyć taki widok:&lt;br /&gt;
&lt;br /&gt;
[[File:Gpsd.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:Gpsd&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Jeżeli pracujemy w środowisku Xów możemy uruchomić graficzna wersję programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
xgps&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i obejrzeć rozmieszczenie satelitów na niebie:&lt;br /&gt;
&lt;br /&gt;
[[File:Xgps.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:xps&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że jeżeli chcielibyśmy ponownie uzyskać &amp;quot;ręczny&amp;quot; dostęp do portu szeregowego należy wcześniej zakończyć pracę demona gpsd, który blokuje możliwość używania portu przez inne programy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo killall gpsd &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ćwiczenia====&lt;br /&gt;
1. Napisz w języku Python parser danych otrzymywanych z GPS. W przypadku niemożliwości uzyskania fixingu użyj poniższych danych testowych:&lt;br /&gt;
&lt;br /&gt;
2. W pliku track.txt znajduje się zarejestrowana trasa zapisana w formacie NEMA. Przeprowadź parsowanie danych, nanieś uzyskane współrzędne i ustal: adres początkowy/końcowy trasy, czas pokonania trasy, średnią i maksymalną prędkość.&lt;br /&gt;
&lt;br /&gt;
3. [Dla zaawansowanych] Przygotuj GPS logger zasilany ogniwem litowym i z jego wykorzystaniem spróbuj zdigitalizować kształt wybranej powierzchni terenu (wybierz miejsce z charakterystyczną rzeźbą np. Pola Mokotowskie, Górkę Szczęśliwicką czy też Skarpę Wiślaną). Z uzyskanych punktów odtwórz trójwymiarowy model rzeźby terenu.&lt;br /&gt;
&lt;br /&gt;
====Wskazówki====&lt;br /&gt;
&lt;br /&gt;
1. Do narysowania danych odczytanych z GPS w postaci trasy na mapie można użyć narzędzia internetowego GPS Visualizer, pozwalającego wczytać dane w formacie NMEA: http://www.gpsvisualizer.com/&lt;br /&gt;
&lt;br /&gt;
====Ciekawostki====&lt;br /&gt;
GPS loggery wykorzystano w badaniu zachowania psów pasterskich i ich sposobów na zaganianie i kontrolowanie stada owiec. Zebrane dane pozwoliły stworzyć model komputerowy odwzorowujący zachowanie psa:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;iframe width=&amp;quot;420&amp;quot; height=&amp;quot;315&amp;quot; src=&amp;quot;https://www.youtube.com/embed/kGynBYD3sbE&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daniel Strömbom, Richard P. Mann, Alan M. Wilson, Stephen Hailes, A. Jennifer Morton, David J. T. Sumpter, Andrew J. King, Solving the shepherding problem: heuristics for herding autonomous, interacting agents, The Royal Society, 2014&lt;br /&gt;
http://rsif.royalsocietypublishing.org/content/11/100/20140719&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Zdalne logowanie na RP, automatyczny start oprogramowania, automatyzacja pomiarów&lt;br /&gt;
*Realizacja projektu zaliczeniowego&lt;br /&gt;
&lt;br /&gt;
====Automatyczny start====&lt;br /&gt;
Czasami zachodzi potrzeba przygotowania komputera Raspberry Pi do automatycznego startu przygotowanych skryptów/programów bez zewnętrznej ingerencji użytkownika. Wówczas możemy uruchomić pożądane pomiary np. w warunkach terenowych bez dysponowania monitorem/klawiaturą/myszką. Do uruchamiania skryptów według harmonogramu lub w przypadku nastąpienia pewnym zdarzeń (np. uruchomienia) możemy użyć programu crone.&lt;br /&gt;
&lt;br /&gt;
W pierwszej kolejności przygotowujemy skrypt uruchamiający o nazwie loggerLauncher.sh i przykładowej zawartości jak niżej:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
#/bin/sh&lt;br /&gt;
&lt;br /&gt;
cd /home/pi/&lt;br /&gt;
sudo python /home/pi/dataLogger.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zmieniamy ustawienia pliku na plik wykonywalny:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
chmod 755 /home/pi/loggerLauncher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Upewniamy się, że skrypt uruchamia się prawidłowo:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sh launcher.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Teraz możemy przygotowany skrypt dodać do zadań crone, otwieramy do edycji listę zadań:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo crontab -e&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i dodajemy następującą linię:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
@reboot sh /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
która spowoduje uruchomienia naszego skryptu przy starcie systemu. Możemy również ustawić cykliczne uruchamianie:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
# Start co 2 minuty&lt;br /&gt;
*/2 * * * * /home/pi/loggerLauncher.sh &amp;gt;/home/pi/cronlog 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zajęcia 6===&lt;br /&gt;
Plan zajęć:&lt;br /&gt;
*Realizacja projektu zaliczeniowego i zaliczenie bloku tematycznego RP.&lt;br /&gt;
&lt;br /&gt;
===Linki===&lt;br /&gt;
http://pi.gadgetoid.com/pinout&lt;br /&gt;
&lt;br /&gt;
https://code.google.com/p/webiopi/&lt;br /&gt;
&lt;br /&gt;
https://www.primianotucci.com/blog/android-on-udoo-quad&lt;br /&gt;
&lt;br /&gt;
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.Delaunay.html&lt;br /&gt;
&lt;br /&gt;
http://www.gpsinformation.org/dale/nmea.htm&lt;br /&gt;
&lt;br /&gt;
===Dokumentacja===&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-1.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 1.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.0-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.0 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
[[Media:Raspberry-Pi-Rev-2.1-Model-AB-Schematics.pdf|Raspberry Pi Revision 2.1 Model AB]] - schemat elektryczny&lt;br /&gt;
&lt;br /&gt;
===Przydatne polecenia Raspbian===&lt;br /&gt;
Uruchomienie Xów: startx&lt;br /&gt;
Login: pi&lt;br /&gt;
Hasło: raspberry&lt;br /&gt;
&lt;br /&gt;
Sprawdzenie ile jest wolnego miejsca na dysku?:&lt;br /&gt;
df -Bm &lt;br /&gt;
Dodaj -h (od ang. &amp;quot;Human readable&amp;quot;), żeby uzyskać informację przeliczoną na megabajty, gigabajty itd.  &lt;br /&gt;
&lt;br /&gt;
Jak zamontować pendrive?&lt;br /&gt;
&lt;br /&gt;
* Podłącz urządzenie &lt;br /&gt;
* Sprawdź jaką nazwę nadał mu system:&lt;br /&gt;
ls /dev/sd*&lt;br /&gt;
* Zamontuj:&lt;br /&gt;
sudo mount -t vfat /dev/sda /mnt/usb&lt;br /&gt;
&lt;br /&gt;
Upewnij się wcześniej, że folder /mnt/usb istnieje, w razie potrzeby utwórz.&lt;br /&gt;
&lt;br /&gt;
Jak wyłączyć Raspberry Pi?&lt;br /&gt;
&lt;br /&gt;
Użyj polecnia: sudo shutdown -h now albo w przypadku żywania LXDE GUI naciśnij czerwony przycisk wyłączenia w menu w prawym górnym rogu ekranu.&lt;br /&gt;
&lt;br /&gt;
====Udostępnianie folderu w sieci Windows====&lt;br /&gt;
&lt;br /&gt;
Instalujemy Sambę:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install samba samba-common-bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tworzymy udostępniany folder:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
mkdir ~/share&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otwieramy do edycji plik konfiguracyjny Samby:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo nano /etc/samba/smb.conf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Upewniamy się, że obsługa udostępniania folderów dla Windows jest włączony, a nazwa grupy roboczej taka do jakiej chcemy dołączyć:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
workgroup = WORKGROUP&lt;br /&gt;
wins support = yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grupa robocza &amp;quot;WORKGROUP&amp;quot; jest domyślną grupą dla Windows.&lt;br /&gt;
&lt;br /&gt;
Na końcu plik konfiguracyjnego dodajemy opis udostępnianego zasobu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
[PiShare]&lt;br /&gt;
 comment=Raspberry Pi Share&lt;br /&gt;
 path=/home/pi/share&lt;br /&gt;
 browseable=Yes&lt;br /&gt;
 writeable=Yes&lt;br /&gt;
 only guest=no&lt;br /&gt;
 create mask=0777&lt;br /&gt;
 directory mask=0777&lt;br /&gt;
 public=no&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parametr &amp;quot;public=no&amp;quot; oznacza, że każdy próbujący uzyskać dostęp do tego zasobu będzie musiał się zalogować. Należy ustawić jeszcze nazwę użytkownika i hasło do logowania do folderu:&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo smbpasswd -a pi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gotowe.&lt;br /&gt;
&lt;br /&gt;
====Jak wykonać zrzut ekranu w Raspbian?====&lt;br /&gt;
&lt;br /&gt;
Najpierw musimy zainstalować narzędzie scrot przeznaczone do tego celu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
sudo apt-get install scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A potem wystarczy je wywołać z linii poleceń w terminalu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zrzut ekranu zostanie zapisany w folderze, w którym aktualnie się znajdujemy. Jeżeli nie chcemy mieć na zrzucie ekranu widocznego okna terminalu możemy zrobić zrzut z zadanym opóźnieniem i zminimalizować w tym czasie terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = 'bash'&amp;gt;&lt;br /&gt;
scrot -d 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==Okulograf ==&lt;br /&gt;
&lt;br /&gt;
===1. Analiza obrazu===&lt;br /&gt;
* Wstęp o analizie obrazu - analizie kilkuwymiarowego sygnału&lt;br /&gt;
** przykłady wykorzystania analizy obrazu: qr codes, kody kreskowe, OCR, okulografia, AR, Microsoft HoloLens&lt;br /&gt;
** przedstawienie obrazu jako macierzy&lt;br /&gt;
** rgb, rgbA, hsv&lt;br /&gt;
** obraz z kamery&lt;br /&gt;
** OpenCV&lt;br /&gt;
* Zadania:&lt;br /&gt;
** podłączyć suwaki OpenCV pod każdy z kanałów B, G, R&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
def nothing(x):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
cam = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
cv2.namedWindow(&amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
cv2.createTrackbar(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;, 0, 255, nothing)&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
      frame = cam.read()[1]&lt;br /&gt;
&lt;br /&gt;
      track_pos = cv2.getTrackbarPos(&amp;quot;name&amp;quot;, &amp;quot;window&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      cv2.imshow(&amp;quot;window&amp;quot;, frame)&lt;br /&gt;
      key = cv2.waitKey(10) &amp;amp; 0xFF&lt;br /&gt;
      if key == 27 or key == ord('q'):&lt;br /&gt;
      	 break&lt;br /&gt;
&lt;br /&gt;
cam.release()&lt;br /&gt;
cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
** przekonwetować obraz BGR do skali szarości&lt;br /&gt;
** narysować histogram&lt;br /&gt;
*** najłatwiej skorzystać z Matplotlib&lt;br /&gt;
*** dla obrazu z kamery należy skorzystać z opci &amp;quot;ion&amp;quot; w matplotlib, aby móc rysować na bieżąco &lt;br /&gt;
*** należy skorzystać z funkcji cv2.calcHist - [http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=cv2.calchist#cv2.calcHist]&lt;br /&gt;
*** wyrównać histogram - [http://pl.wikipedia.org/wiki/Wyr%C3%B3wnanie_histogramu]&lt;br /&gt;
** zaimplementować własny filtr&lt;br /&gt;
** wykrywanie danego obiektu po kolorze - konwersja na hsv - [http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#object-tracking]&lt;br /&gt;
** dorysowanie obiektu na obrazie poruszającego się razem z wykrytym obiektem&lt;br /&gt;
*** np. kółko - [http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle]&lt;br /&gt;
&lt;br /&gt;
===2. Okulografia===&lt;br /&gt;
* Wstęp teoretyczny&lt;br /&gt;
** Co to są okulografy, jak działają i komu mogą pomóc.&lt;br /&gt;
** Dlaczego potrzebna jest korekcja ruchu głowy.&lt;br /&gt;
** Dlaczego obsługa interfejsu okulografem jest trudna - rozwiązania od Tobii i wykrywania ruchu głowy jako alternatywa.&lt;br /&gt;
** Eviacam - duzy projekt wykorzystujący bibliotekę OpenCV do wykrywania głowy i obsługi myszki&lt;br /&gt;
* Ergonomia oraz badanie&lt;br /&gt;
** Obsługa okulografu na kiju i Tobii&lt;br /&gt;
** Obsługa aplikacji do pisania i aplikacji do rysowania z projektu PISAK za pomocą okulografów oraz Eviacam-a(ruchy głową) &lt;br /&gt;
** Ankieta ergonomiczności - używanie Tobii, używanie eyetracker-a na kiju, używanie Eviacam-a&lt;br /&gt;
&lt;br /&gt;
===Zadanie dodatkowe dla chętnych===&lt;br /&gt;
Zaprojektowanie interfejsu do obsługi okulografem w oparciu o engine PISAKa&lt;br /&gt;
&lt;br /&gt;
* Projektowanie interfejsu w PISAKu:&lt;br /&gt;
** widgets - moduły funkcjonalne PISAKa&lt;br /&gt;
** handlers - funkcje podłączane do przycisku&lt;br /&gt;
** jsony - składanie różnych modułów funkcjonalnych w jeden interfejs&lt;br /&gt;
** css-y - edycja wyglądu interfejsu &lt;br /&gt;
* stworzenie własnego/zmodyfikowanie istniejącego interfejsu z myślą o obsłudze okulografem&lt;br /&gt;
* praca nad własnym interfejsem&lt;br /&gt;
* porównanie interfejsów&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7691</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7691"/>
		<updated>2018-04-11T07:20:14Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import KinectDataReader&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '......'&lt;br /&gt;
file_name = '......'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7689</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7689"/>
		<updated>2018-04-04T08:38:12Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '......'&lt;br /&gt;
file_name = '......'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7688</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7688"/>
		<updated>2018-04-04T08:36:45Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:3D_Kinect_ENG.pdf&amp;diff=7687</id>
		<title>Plik:3D Kinect ENG.pdf</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:3D_Kinect_ENG.pdf&amp;diff=7687"/>
		<updated>2018-04-04T08:08:45Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7686</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7686"/>
		<updated>2018-04-04T08:08:29Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Pomiary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych.&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7685</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7685"/>
		<updated>2018-04-04T08:06:41Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przygotowanie danych do analizy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwszy kanał to próbki czasu wyrażone w [s] natomiast pozostałe kanały to dane z kolejnych sensorów TR, BR, TL, BL (górny prawy-TR, dolny prawy-BR, górny lewy-TL, dolny lewy-BL).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TR = wbr.get_samples()[0,:]&lt;br /&gt;
BR = wbr.get_samples()[1,:]&lt;br /&gt;
TL = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TR = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
TL = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of pressure'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7684</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7684"/>
		<updated>2018-04-04T06:33:30Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych.&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=implementacja klasy|text=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7683</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7683"/>
		<updated>2018-04-04T06:33:01Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych.&lt;br /&gt;
&lt;br /&gt;
{{Solution|title=|text=implementacja klasy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{clear}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7682</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7682"/>
		<updated>2018-04-04T06:29:47Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class KinectException(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
class JointStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(JointStruct, self).__init__('iffffff')&lt;br /&gt;
&lt;br /&gt;
class HandStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HandStruct, self).__init__('ifffff')&lt;br /&gt;
&lt;br /&gt;
class UserStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(UserStruct, self).__init__('hfffi')&lt;br /&gt;
&lt;br /&gt;
class FrameStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(FrameStruct, self).__init__('iQ')&lt;br /&gt;
&lt;br /&gt;
class HeaderStruct(struct.Struct):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super(HeaderStruct, self).__init__('i??diQiQ')&lt;br /&gt;
&lt;br /&gt;
class Point3Mock(object):&lt;br /&gt;
    def __init__(self, x, y, z):&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
&lt;br /&gt;
class JointMock(object):&lt;br /&gt;
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = id&lt;br /&gt;
        self.positionConfidence = positionConfidence&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class SkeletonFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.user_id = user_id&lt;br /&gt;
        self.user_x = x&lt;br /&gt;
        self.user_y = y&lt;br /&gt;
        self.user_z = z&lt;br /&gt;
        self.user_state = user_state&lt;br /&gt;
        self.joints = joints&lt;br /&gt;
&lt;br /&gt;
class HandDataMock(object):&lt;br /&gt;
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):&lt;br /&gt;
        self.id = hand_id&lt;br /&gt;
        self.x = x&lt;br /&gt;
        self.y = y&lt;br /&gt;
        self.z = z&lt;br /&gt;
        self.x_converted = x_converted&lt;br /&gt;
        self.y_converted = y_converted&lt;br /&gt;
&lt;br /&gt;
class HandFrameMock(object):&lt;br /&gt;
    def __init__(self, frame_index, frame_timestamp, hands):&lt;br /&gt;
        self.frame_index = frame_index&lt;br /&gt;
        self.frame_timestamp = frame_timestamp&lt;br /&gt;
        self.hands = hands&lt;br /&gt;
&lt;br /&gt;
class Serialization(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.joint_s = JointStruct()&lt;br /&gt;
        self.hand_s = HandStruct()&lt;br /&gt;
        self.user_s = UserStruct()&lt;br /&gt;
        self.frame_s = FrameStruct()&lt;br /&gt;
        self.header_s = HeaderStruct()&lt;br /&gt;
&lt;br /&gt;
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):&lt;br /&gt;
        buf = self.header_s.pack(*header)&lt;br /&gt;
        buf += self.serialize_skeleton(user_frame, frame_index)&lt;br /&gt;
        buf += self.serialize_hands(hand_frame, frame_index)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_frame(self, data_file):&lt;br /&gt;
        data = []&lt;br /&gt;
        try:&lt;br /&gt;
            data += self.header_s.unpack(data_file.read(self.header_s.size))&lt;br /&gt;
            data.append(self.unserialize_skeleton(data_file))&lt;br /&gt;
            data.append(self.unserialize_hands(data_file))&lt;br /&gt;
        except struct.error:&lt;br /&gt;
            return&lt;br /&gt;
        return data&lt;br /&gt;
&lt;br /&gt;
    def register_hand_coordinates(self, convert_hand_coordinates):&lt;br /&gt;
        self.convert_hand_coordinates = convert_hand_coordinates&lt;br /&gt;
&lt;br /&gt;
    def register_joint_coordinates(self, convert_joint_coordinates):&lt;br /&gt;
        self.convert_joint_coordinates = convert_joint_coordinates&lt;br /&gt;
&lt;br /&gt;
    def serialize_hands(self, hand_frame, frame_index):&lt;br /&gt;
        if hand_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)&lt;br /&gt;
            hands = hand_frame.hands&lt;br /&gt;
            if hands:&lt;br /&gt;
                if len(hands) == 1:&lt;br /&gt;
                    hand = hands[0]&lt;br /&gt;
                    if hand.isTracking():&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
                    else:&lt;br /&gt;
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
                else:&lt;br /&gt;
                    for hand in hands[:2]:&lt;br /&gt;
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)&lt;br /&gt;
                        buf += self.hand_s.pack(hand.id,&lt;br /&gt;
                                                hand.position.x,&lt;br /&gt;
                                                hand.position.y,&lt;br /&gt;
                                                hand.position.z,&lt;br /&gt;
                                                x_new,&lt;br /&gt;
                                                y_new)&lt;br /&gt;
            else:&lt;br /&gt;
                for i in range(2):&lt;br /&gt;
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            for i in range(2):&lt;br /&gt;
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def serialize_joint(self, joint):&lt;br /&gt;
        if joint is not None:&lt;br /&gt;
            pos = joint.position&lt;br /&gt;
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)&lt;br /&gt;
            return self.joint_s.pack(joint.type,&lt;br /&gt;
                                     joint.positionConfidence,&lt;br /&gt;
                                     joint.position.x,&lt;br /&gt;
                                     joint.position.y,&lt;br /&gt;
                                     joint.position.z,&lt;br /&gt;
                                     x_new,&lt;br /&gt;
                                     y_new)&lt;br /&gt;
        else:&lt;br /&gt;
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
    def serialize_skeleton(self, user_frame, frame_index):&lt;br /&gt;
        if user_frame is not None:&lt;br /&gt;
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)&lt;br /&gt;
            users = user_frame.users&lt;br /&gt;
            if users:&lt;br /&gt;
                user = users[0]&lt;br /&gt;
                user_coordinates = user.centerOfMass&lt;br /&gt;
                state = int(user.skeleton.state)&lt;br /&gt;
                buf += self.user_s.pack(user.id,&lt;br /&gt;
                                        user_coordinates.x,&lt;br /&gt;
                                        user_coordinates.y,&lt;br /&gt;
                                        user_coordinates.z,&lt;br /&gt;
                                        state)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(user.skeleton[JointType(i)])&lt;br /&gt;
            else:&lt;br /&gt;
                buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
                for i in range(15):&lt;br /&gt;
                    buf += self.serialize_joint(None)&lt;br /&gt;
        else:&lt;br /&gt;
            buf = self.frame_s.pack(0, 0)&lt;br /&gt;
            buf += self.user_s.pack(0, 0, 0, 0, 0)&lt;br /&gt;
            for i in range(15):&lt;br /&gt;
                buf += self.serialize_joint(None)&lt;br /&gt;
        return buf&lt;br /&gt;
&lt;br /&gt;
    def unserialize_hands(self, f):&lt;br /&gt;
        v = self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        data = []&lt;br /&gt;
        for i in range(2):&lt;br /&gt;
            hands = self.hand_s.unpack(f.read(self.hand_s.size))&lt;br /&gt;
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))&lt;br /&gt;
        return HandFrameMock(v[0], v[1], data)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_joint(self, f):&lt;br /&gt;
        v = self.joint_s.unpack(f.read(self.joint_s.size))&lt;br /&gt;
        return JointMock(*v)&lt;br /&gt;
&lt;br /&gt;
    def unserialize_skeleton(self, f):&lt;br /&gt;
        v = []&lt;br /&gt;
        v += self.frame_s.unpack(f.read(self.frame_s.size))&lt;br /&gt;
        v += self.user_s.unpack(f.read(self.user_s.size))&lt;br /&gt;
        joints = []&lt;br /&gt;
        for i in range(15):&lt;br /&gt;
            joints.append(self.unserialize_joint(f))&lt;br /&gt;
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)&lt;br /&gt;
        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7681</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7681"/>
		<updated>2018-04-04T06:25:15Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7680</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7680"/>
		<updated>2018-04-03T22:30:08Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Plan zajęć */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań &amp;lt;br&amp;gt;&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import sys&lt;br /&gt;
sys.path.append('/usr/share/openbci/drivers/kinect/')&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7679</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7679"/>
		<updated>2018-04-03T22:04:26Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Plan zajęć */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań\\&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import sys&lt;br /&gt;
sys.path.append('/usr/share/openbci/drivers/kinect/')&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7678</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7678"/>
		<updated>2018-04-03T22:04:07Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Plan zajęć */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import sys&lt;br /&gt;
sys.path.append('/usr/share/openbci/drivers/kinect/')&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:3D_Kinect.pdf&amp;diff=7677</id>
		<title>Plik:3D Kinect.pdf</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:3D_Kinect.pdf&amp;diff=7677"/>
		<updated>2018-04-03T21:37:38Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: Gbernatowicz przesłał nową wersję Plik:3D Kinect.pdf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:KinectAppStart.png&amp;diff=7676</id>
		<title>Plik:KinectAppStart.png</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:KinectAppStart.png&amp;diff=7676"/>
		<updated>2018-04-03T20:44:08Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Plik:KinectApp.png&amp;diff=7675</id>
		<title>Plik:KinectApp.png</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Plik:KinectApp.png&amp;diff=7675"/>
		<updated>2018-04-03T20:43:35Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7674</id>
		<title>Nowe technologie w fizyce biomedycznej/Kamery 3D</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Kamery_3D&amp;diff=7674"/>
		<updated>2018-04-03T20:42:49Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Pomiary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kamery 3D =&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Budowa i zasada działania sensora Kinect.&lt;br /&gt;
**Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.&lt;br /&gt;
**Profesjonalne systemy do rejestracji ruchu&lt;br /&gt;
**Zastosowania w biomechanice oraz rehabilitacji.&lt;br /&gt;
*Zapoznanie się z działaniem sensora Kinect&lt;br /&gt;
*Pomiary:&lt;br /&gt;
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL). &lt;br /&gt;
&lt;br /&gt;
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Zaprezentowanie uzyskanych wyników&lt;br /&gt;
&lt;br /&gt;
==Sensor Kinect==&lt;br /&gt;
&lt;br /&gt;
Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.&lt;br /&gt;
&lt;br /&gt;
Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:kinect.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Sensor Kinect Xbox 360.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Budowa sensora Kinect Xbox 360 (&amp;lt;xr id=&amp;quot;fig:kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;):&lt;br /&gt;
*kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,&lt;br /&gt;
*kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,&lt;br /&gt;
*emiter podczerwieni - emituje wiązkę promieni podczerwonych,&lt;br /&gt;
*4 mikrofony kierunkowe -  wykorzystywane przez funkcje rozpoznawania mowy,&lt;br /&gt;
*napęd umożliwiający ruch głowicą z akcelerometrem.&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.&lt;br /&gt;
&lt;br /&gt;
[[Plik:KinectApp.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:KinectAppStart.png|100px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]&lt;br /&gt;
&lt;br /&gt;
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui &amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.&lt;br /&gt;
Scenariusz do rejestracji danych przy pomocy sensora Kinect pokazany został poniżej (&amp;lt;xr id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;). Umożliwia on rejestrację w trybie ''online'', i wówczas zarówno obraz RGB, jak mapa głębokości mogą zostać zapisane w domyślnym formacie .oni. Dodatkowo tworzony jest plik binarny .algs z metadanymi rejestracji, gdzie zapisywane są między innymi współrzędne wyestymowanych pozycji anatomicznych. Tryb ''offline'' umożliwa odtwarzanie plików .oni oraz .algs. W przypadku rejestracji w trybie ''online'' w scenariuszu zmieniamy następujące parametry:&lt;br /&gt;
&lt;br /&gt;
       capture_raw = 1		        – zapis obrazu do pliku .oni (0 lub 1)&lt;br /&gt;
       out_raw_file_path = test.oni	– nazwa pliku .oni&lt;br /&gt;
       capture_hands = 1                 – zapis pozycji rąk (0 lub 1)&lt;br /&gt;
       capture_skeleton = 1		– zapis pozycji anatomicznych (0 lub 1)&lt;br /&gt;
       out_algs_file_path = test.algs	– nazwa pliku .algs z metadanymi rejestracji&lt;br /&gt;
&lt;br /&gt;
Wybierając tryb ''offline'' należy podać odpowiednią ścieżkę do plików .oni oraz .algs:&lt;br /&gt;
 &lt;br /&gt;
       in_raw_file_path = test.oni&lt;br /&gt;
       in_algs_file_path = test.algs&lt;br /&gt;
&lt;br /&gt;
Wszystkie pliki zapisywane są w lokalizacji: /home/.obci/sandbox&lt;br /&gt;
&lt;br /&gt;
[[Plik:obci_gui.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Drop Vertical Jump ===&lt;br /&gt;
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.&lt;br /&gt;
&lt;br /&gt;
[[Plik:drop_vertical_jump.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:obci_kinect&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]. &lt;br /&gt;
&lt;br /&gt;
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:&lt;br /&gt;
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF&lt;br /&gt;
[[Plik:KVM.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Knee valgus motion]]&lt;br /&gt;
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF&lt;br /&gt;
[[Plik:FPKA.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Frontal plane knee angle]]&lt;br /&gt;
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF&lt;br /&gt;
[[Plik:KASR.png|400px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;knee-to-ankle separation ration]]&lt;br /&gt;
*zmiana w czasie średniej pozycji bioder, kolan i stóp.&lt;br /&gt;
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.&lt;br /&gt;
&lt;br /&gt;
===Analiza danych===&lt;br /&gt;
&lt;br /&gt;
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import sys&lt;br /&gt;
sys.path.append('/usr/share/openbci/drivers/kinect/')&lt;br /&gt;
from KinectUtils import Serialization&lt;br /&gt;
&lt;br /&gt;
class KinectDataReader(object):&lt;br /&gt;
    def __init__(self, file_name):&lt;br /&gt;
        super(KinectDataReader, self).__init__()&lt;br /&gt;
        self.file_name = file_name&lt;br /&gt;
        self.in_algs_file = open(self.file_name + '.algs', 'rb')&lt;br /&gt;
        self._s = Serialization()&lt;br /&gt;
&lt;br /&gt;
    def readNextFrame(self):&lt;br /&gt;
        return self._s.unserialize_frame(self.in_algs_file)&lt;br /&gt;
&lt;br /&gt;
first_time = 0&lt;br /&gt;
joints = []&lt;br /&gt;
Time = []&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    file_name = sys.argv[1]&lt;br /&gt;
except Exception:&lt;br /&gt;
    file_name = 'test'&lt;br /&gt;
&lt;br /&gt;
kinect = KinectDataReader(FILE_PATH+file_name)&lt;br /&gt;
while True:&lt;br /&gt;
    frame = kinect.readNextFrame()&lt;br /&gt;
    if frame is None:&lt;br /&gt;
        print('END OF FILE')&lt;br /&gt;
        break&lt;br /&gt;
 &lt;br /&gt;
    frame_index = frame[0]&lt;br /&gt;
    hands_included = frame[1]&lt;br /&gt;
    skeleton_included = frame[2]&lt;br /&gt;
    frame_time = frame[3]&lt;br /&gt;
 &lt;br /&gt;
    if not first_time:&lt;br /&gt;
        first_time = frame_time&lt;br /&gt;
&lt;br /&gt;
    if skeleton_included:&lt;br /&gt;
        skel = frame[8]&lt;br /&gt;
        Time.append(frame_time-first_time)&lt;br /&gt;
        joints.append(skel.joints)&lt;br /&gt;
&lt;br /&gt;
        print('Idx:', frame_index, 'Time:', frame_time-first_time)&lt;br /&gt;
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)&lt;br /&gt;
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:&lt;br /&gt;
&lt;br /&gt;
    joints = [JOINT_HEAD,&lt;br /&gt;
              JOINT_NECK,&lt;br /&gt;
              JOINT_RIGHT_SHOULDER,&lt;br /&gt;
              JOINT_LEFT_SHOULDER,&lt;br /&gt;
              JOINT_RIGHT_ELBOW,&lt;br /&gt;
              JOINT_LEFT_ELBOW,&lt;br /&gt;
              JOINT_RIGHT_HAND,&lt;br /&gt;
              JOINT_LEFT_HAND,&lt;br /&gt;
              JOINT_TORSO,&lt;br /&gt;
              JOINT_RIGHT_HIP,&lt;br /&gt;
              JOINT_LEFT_HIP,&lt;br /&gt;
              JOINT_RIGHT_KNEE,&lt;br /&gt;
              JOINT_LEFT_KNEE,&lt;br /&gt;
              JOINT_RIGHT_FOOT,&lt;br /&gt;
              JOINT_LEFT_FOOT]&lt;br /&gt;
&lt;br /&gt;
Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].&lt;br /&gt;
[[Plik:Uklad_jointow.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:kinect_joints&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Układ pozycji anatomicznych.]]&lt;br /&gt;
&lt;br /&gt;
===Literatura===&lt;br /&gt;
*Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.&lt;br /&gt;
*Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7577</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7577"/>
		<updated>2018-02-28T09:32:39Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych: stanie swobodne */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwsze 4 kanały to dane z kolejnych sensorów (górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL), natomiast 5 kanał to próbki czasu wyrażone w [s].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TL = wbr.get_samples()[0,:]&lt;br /&gt;
TR = wbr.get_samples()[1,:]&lt;br /&gt;
BR = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of pressure'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7576</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7576"/>
		<updated>2018-02-28T09:24:04Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych: wychylenia dynamiczne */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwsze 4 kanały to dane z kolejnych sensorów (górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL), natomiast 5 kanał to próbki czasu wyrażone w [s].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TL = wbr.get_samples()[0,:]&lt;br /&gt;
TR = wbr.get_samples()[1,:]&lt;br /&gt;
BR = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of posture'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej płaszczyźnie AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7575</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7575"/>
		<updated>2018-02-28T09:23:48Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Analiza danych: stanie swobodne */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwsze 4 kanały to dane z kolejnych sensorów (górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL), natomiast 5 kanał to próbki czasu wyrażone w [s].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TL = wbr.get_samples()[0,:]&lt;br /&gt;
TR = wbr.get_samples()[1,:]&lt;br /&gt;
BR = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of posture'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz płaszczyźnie AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej przestrzeni AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7574</id>
		<title>Nowe technologie w fizyce biomedycznej/Posturografia</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=Nowe_technologie_w_fizyce_biomedycznej/Posturografia&amp;diff=7574"/>
		<updated>2018-02-28T09:22:14Z</updated>

		<summary type="html">&lt;p&gt;Gbernatowicz: /* Przygotowanie danych do analizy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Posturograf =&lt;br /&gt;
&lt;br /&gt;
Zajęcia warsztatowe składające się z wprowadzającego w tematykę zajęć wykładu i indywidualnych ćwiczeń wykonywanych przez studentów. Studenci w czasie zajęć przeprowadzają standardowe pomiary posturograficzne, a następnie analizują zebrane dane.&lt;br /&gt;
&lt;br /&gt;
==Plan zajęć==&lt;br /&gt;
&lt;br /&gt;
Zajęcia 1:&lt;br /&gt;
*Wstęp teoretyczny:&lt;br /&gt;
**Wii Balance Board (budowa, główne biblioteki obsługujące sensor, zastosowania)&lt;br /&gt;
**Projesjonalne systemy do rejestracji siły nacisku&lt;br /&gt;
**Równowaga a stabilność posturalna&lt;br /&gt;
**Podstawowe zadania posturograficzne&lt;br /&gt;
**Opis wybranych wskaźników do zadań posturograficznych&lt;br /&gt;
*Wprowadzenie do pomiarów przeprowadzanych na zajęciach (zapoznanie się z wybranymi scenariuszami oraz modułami do analizy)&lt;br /&gt;
*Zapoznanie się z działaniem Wii Balance Board&lt;br /&gt;
*Przeprowadzenie pomiarów&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoard.pdf]] Informacje wstępne oraz opis zadań&lt;br /&gt;
&lt;br /&gt;
[[Media: WiiBoardENG.pdf]] Introduction and task description in English&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[[Media:wprowadzenie.pdf]] Wykład z zajęć wprowadzających&lt;br /&gt;
[[Media:Pomiary_wii.pdf]] Wstęp do pomiarów posturograficznych&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zajęcia 2,3,4:&lt;br /&gt;
*Analiza zebranych danych&lt;br /&gt;
*Prezentacja wyników&lt;br /&gt;
&lt;br /&gt;
==Pomiary==&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu (na Ubuntu 16.04). Opis architektury systemu OpenBCI oraz podręcznik użytkownika Brain4edu dostępne są na stronie http://laboratorium-eeg.braintech.pl/. Z samego OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]. &lt;br /&gt;
&lt;br /&gt;
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów posturograficznych wybieramy opcję 'Wii App', która otworzy okno z wyborem scenariuszy.&lt;br /&gt;
&lt;br /&gt;
[[Plik:brain4edu.png|300px|thumb|left|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Interfejs graficzny aplikacji Brain4edu]]&lt;br /&gt;
[[Plik:wiiApp.png|300px|thumb|right|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Okno wyboru scenariuszy eksperymentalnych aplikacji WiiApp]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Pomiary przeprowadzane są w środowisku OpenBCI. Architektura systemu oraz opis wybranych scenariuszy jest dostępny na stronie http://bci.fuw.edu.pl/wiki/Tutorials.  Szczegółowe informacje dotyczące konfiguracji OpenBCI na Ubuntu 14.04 LTS można znaleźć pod adresem http://deb.braintech.pl/. Po zainstalowaniu pakietów źródła znajdą sie w katalogu &amp;lt;tt&amp;gt;/usr/share/openbci&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Z OpenBCI można również korzystać na systemie Windows -&amp;gt; instrukcja [[Media: obci_Windows.pdf]]&lt;br /&gt;
&lt;br /&gt;
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;$ obci_gui --presets new_tech &amp;lt;/source&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Podczas zajęć przeprowadzone zostaną następujące pomiary:&lt;br /&gt;
*stanie swobodne z oczami otwartymi/zamkniętymi,&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej dla badanego (w przód, w tył, w prawo, w lewo),&lt;br /&gt;
*wychylenia szybkie i &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną dla badanego (w przód, w tył, w prawo, w lewo).&lt;br /&gt;
&lt;br /&gt;
W wyniku każdego pomiaru otrzymujemy komplet trzech plików (domyślna lokalizacja to Katalog Domowy): &lt;br /&gt;
* Plik z sygnałem (.raw) zapisanym w formacie binarnym. W pliku znajdują się próbki z pięciu kanałów – wartości z czterech czujników WBB oraz momenty w czasie (w sekundach) mierzone względem pojawienia się pierwszej próbki.&lt;br /&gt;
* Plik z metadanymi (.xml), w którym znajdują się szczegółowe informacje dotyczące rejestracji (nazwy kanałów, częstość próbkowania, całkowita liczba próbek itp.).&lt;br /&gt;
* Plik ze znacznikami (.tag), w którym zapisywane są momenty kolejnych zdarzeń (np. początek i koniec wykonywania zadania) zsynchronizowane z sygnałem. Każdy znacznik posiada charakterystyczną nazwę, moment wystąpienia w sygnale, długość oraz ewentualnie opis. &lt;br /&gt;
&amp;lt;!--W przypadku zadań z informacją zwrotną dla badanego generowane są dwa pliki ze znacznikami. Interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analiza danych==&lt;br /&gt;
&lt;br /&gt;
===Przygotowanie danych do analizy===&lt;br /&gt;
Pierwszym etapem analizy jest wczytanie danych. Korzystamy tutaj z funkcji klasy ReadManager. Otrzymany obiekt posiadaja metodę 'get_samples', która zwraca macierz 5-kanałową. Pierwsze 4 kanały to dane z kolejnych sensorów (górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL), natomiast 5 kanał to próbki czasu wyrażone w [s].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
TL = wbr.get_samples()[0,:]&lt;br /&gt;
TR = wbr.get_samples()[1,:]&lt;br /&gt;
BR = wbr.get_samples()[2,:]&lt;br /&gt;
BL = wbr.get_samples()[3,:]&lt;br /&gt;
TIME = wbr.get_samples()[4,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze przed pobraniem próbek, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments' przyjmująca obiekt klasy ReadManager i znaczniki początkowe i końcowe, a zwracająca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, również posiada metodę 'get_samples'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.signal_processing import read_manager&lt;br /&gt;
from obci.signal_processing.balance.wii_preprocessing import *&lt;br /&gt;
from obci.signal_processing.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
file_name = 'still_eyes_closed_eyes_open'&lt;br /&gt;
wbr = read_manager.ReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.obci.tag')&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na podstawie danch z czterech czujników można wyznaczyć wartości wychyleń w kierunkach x i y  (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_eyes_closed_start', 'ss_eyes_closed_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'start_fast', 'stop_fast'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'baseline_start', 'baseline_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['value'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['value'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Pierwszym etapem analizy jest wstępne przetworzenie danych. W tym celu należy wyestymować rzeczywistą częstość próbkowania Fs (w idealnym przypadku wynosi ona 65 Hz) oraz przepróbkować sygnał do częstości fs ok. 30 Hz (wychylenia swobodne widoczne są głównie w niższych częstościach).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = file_path+file_name&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '/home/newtech/'&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-04_15-02-01' #przykładowa nazwa pliku&lt;br /&gt;
&lt;br /&gt;
#wczytanie danych&lt;br /&gt;
wbr_baseline = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
#estymacja częstości próbkowania Fs                                  &lt;br /&gt;
Fs = analysis_baseline.estimate_fs(wbr_baseline.mgr.get_channel_samples('TSS')) &lt;br /&gt;
#wpisanie częstości Fs do obiektu&lt;br /&gt;
wbr_baseline.mgr.set_param('sampling_frequency', Fs)   &lt;br /&gt;
#przepróbkowanie z czynnikiem 2                         &lt;br /&gt;
wbr_baseline = wii_downsample_signal(wbr_baseline, factor=2, pre_filter=True, use_filtfilt=True) &lt;br /&gt;
#odczytanie nowej częstości próbkowania fs&lt;br /&gt;
fs = float(wbr_baseline.mgr.get_param('sampling_frequency'))                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Po takich operacjach dane przechowywane w obiekcie 'wbr_baseline' klasy WBBReadManager są gotowe do użycia. Klasa ta posiada metodę 'get_raw_signal', która zwraca 4-kanałową macierz z danymi z 4 czujników (są to kanały odpowiadające kolejno czujnikom: górny lewy-TL, górny prawy-TR, dolny prawy-BR, dolny lewy-BL). Można wyznaczyć wartości wychyleń w kierunkach x i y na podstawie informacji z czterech czujników (&amp;lt;xr id=&amp;quot;fig:wbb&amp;quot;&amp;gt;rys. %i&amp;lt;/xr&amp;gt;).:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;x=\frac{(TR+BR)-(TL+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;y=\frac{(TR+TL)-(BR+BL)}{TR+TL+BL+BR}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Należy pamiętać, że dane z czujników pochodzą z układu odniesienia deski Wii Board - zatem uzyskane wartości x i y mieszczą się w zakresie od -1 do 1. Aby uzyskać dane w cm trzeba przemnożyć współrzędne x i y przez odpowiednie czynniki:&lt;br /&gt;
[[Plik:wbb_axes.png|600px|thumb|center|&amp;lt;figure id=&amp;quot;fig:wbb&amp;quot;&amp;gt;&amp;lt;/figure&amp;gt;Wii Balance Board z oznaczonymi płaszczyznami ML i AP. TR, TL, BR, BL ozanczają pozycje czterech czujników.]]&lt;br /&gt;
&lt;br /&gt;
Jednak w przypadku niektórych zadań należy jeszcze, przed wyznaczaniem x i y, odpowiednio wyciąć interesujące nas dane względem znaczników. Czynność tę wykonuje funkcja 'wii_cut_fragments', która zwraca listę obiektów 'smart_tags'. Liczba tych obiektów odpowiada liczbie zdarzeń z danym znacznikiem (dla stania swobodnego lista będzie miała tylko jeden element, natomiast dla wielokrotnych wychyleń będzie ich kilka). Każdy element na tej liście, posiada metodę 'get_samples' zwracającą dane w macierzy 7 kanałowej. W pierwszych 4 kanałach znajdują się dane z czujników TL,TR,BR,BL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
smart_tags = wii_cut_fragments(wbr_baseline, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
TL = smart_tags[0].get_samples()[0,:]&lt;br /&gt;
TR = smart_tags[0].get_samples()[1,:]&lt;br /&gt;
BR = smart_tags[0].get_samples()[2,:]&lt;br /&gt;
BL = smart_tags[0].get_samples()[3,:]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znaczniki 'start_tag_name' oraz 'end_tags_names' dla poszczególnych pomiarów:&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne oczy otwarte: 'ss_start', 'ss_stop'&lt;br /&gt;
* stanie swobodne oczy zamknięte: 'ss_oczy_start', 'ss_oczy_stop'&lt;br /&gt;
&lt;br /&gt;
* wychylenia szybkie bez informacji zwrotnej: 'szybkie_start', 'szybkie_stop'&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; bez informacji zwrotnej: 'start', 'stop'&lt;br /&gt;
&lt;br /&gt;
* stanie swobodne jako kalibracja do zadań z informacją zwrotną: 'ss_start', 'ss_stop'&lt;br /&gt;
* wychylenia szybkie z informacją zwrotną: nie ma znaczników - ciągły zapis danych&lt;br /&gt;
* wychylenia &amp;quot;z przytrzymaniem&amp;quot; z informacją zwrotną: 'start_1', 'finish'&lt;br /&gt;
&lt;br /&gt;
Podczas wczytywania danych z informacją zwrotną interesujące nas informacje znajdują się w pliku z rozszerzeniem .game.tag. Zatem należy ustawić parametr 'tag_format' w wywołaniu funkcji read_file na 'game' (zamiast domyślnie ustawionego 'obci'). Znaczniki czasowe gry nie są zsynchronizowane z sygnałem, ponieważ gra uruchamiana jest w osobnym wątku, który nie ma możliwości komunikacji z multiplekserem. Z tego względu każdy znacznik zapisany w tym pliku posiada czas systemowy, który należy wyrównać względem pierwszej próbki w sygnale. Procedura ta została zaimplementowana w poniższej funkcji, którą należy wykonać przed przepróbkowaniem sygnału:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
wbr_sway.mgr = analysis_helper.set_first_timestamp(wbr_sway.mgr)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dalsze kroki przygotowania danych do analizy wykonujemy tak samo. Dla przypadku wychyleń &amp;quot;z przytrzymaniem&amp;quot; obiekty w liście zwróconej przez funkcję 'wii_cut_fragments' odpowiadają kolejnym realizacjom zadania. Mają one jednak nieco inną strukturę. Oprócz metody 'get_samples()', za pomocą której tak jak poprzednio wczytamy dane z 4 czujników, posiadają również metody:&lt;br /&gt;
*'get_end_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o tym czy zadanie zostało wykonane poprawnie (0-niepoprawnie, 1-poprawnie)&lt;br /&gt;
*'get_start_tag()' - zwraca strukturę, która w polu ['desc']['type'] przechowuje informację o kierunku wychylenia (pole 'direction', wartości: 'up','down','left','right') oraz o poziomie trudności zadania (pole 'level'). Aby wydobyć informację o kierunku wychylenia (analogicznie dla poziomiu trudności) można skorzystać z funkcji: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
eval(smart_tags[index].get_start_tag()['desc']['type'])['direction']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Informacje o poziomie trudności, poprawności wykonania zadania oraz kierunku będą potrzebne do podjęcia decyzji, które próby wykonania zadania będą brane do dalszej analizy. Interesują nas jedynie te poprawne o najwyższym poziomie trudności w każdym z kierunków. &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;!--Dokumentacja funkcji klasy WBBReadManager (przy pomcy której wczytujemy dane. Korzysta ona z obiektu klasy ReadManager, która została zaprojektowana do wczytywania i segmentacji danych rejestrowanych przy pomocy systemu OpenBCI. Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_preprocessing&amp;lt;/tt&amp;gt; umożliwia dodatkowo przepróbkowanie oraz filtrację danych): &lt;br /&gt;
&lt;br /&gt;
*Przepróbkowanie danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy WBBReadManager&lt;br /&gt;
# factor        - nowa_fs = fs / factor (int)&lt;br /&gt;
# pre_filter    - True/False w zależności czy ma być użyty filtr dolnoprzepustowy z częstością&lt;br /&gt;
#                 odcięcia: częstość próbkowania / 2&lt;br /&gt;
# use_filtfilt  - True/False w zależności czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przepróbkowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
factor = 2&lt;br /&gt;
pre_filter = False&lt;br /&gt;
use_filtfilt = True&lt;br /&gt;
&lt;br /&gt;
wbb_mgr = wii_downsample_signal(wbb_mgr, &lt;br /&gt;
                                factor, &lt;br /&gt;
                                pre_factor, &lt;br /&gt;
                                use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Segmentacja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr         - obiekt klasy WBBReadManager,&lt;br /&gt;
# start_tag_name  - nazwa znacznika określającego początek fragmentu,&lt;br /&gt;
# end_tags_names  - lista z nazwami znaczników określających koniec fragmentu.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy SmartTagsManager.&lt;br /&gt;
&lt;br /&gt;
smart_tags = wii_cut_fragments(wbb_mgr,&lt;br /&gt;
                               start_tag_name='start', &lt;br /&gt;
                               end_tags_names=['stop'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Filtracja danych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr       - obiekt klasy  WBBReadManager&lt;br /&gt;
# cutoff_upper  - częstość odcięcia (float)&lt;br /&gt;
# order         - rząd filtru (int)&lt;br /&gt;
# use_filtfilt  - True/False w zależności, czy ma być użyta procedura &lt;br /&gt;
#                 filtrowania filtfilt/lfilter (bool)&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca obiekt klasy WBBReadManager z przefiltrowanym sygnałem.&lt;br /&gt;
&lt;br /&gt;
cutoff_upper = 20&lt;br /&gt;
order = 2&lt;br /&gt;
use_filtfilt = False&lt;br /&gt;
wbb_mgr = wii_filter_signal(wbb_mgr, &lt;br /&gt;
                            cutoff_upper, &lt;br /&gt;
                            order, &lt;br /&gt;
                            use_filtfilt)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: stanie swobodne===&lt;br /&gt;
&lt;br /&gt;
W przypadku stania swobodnego z oczami zamkniętymi oraz otwartymi, studenci mają za zadanie wyznaczyć następujące wskaźniki posturograficzne:&lt;br /&gt;
&amp;lt;!-- (korzystając z funkcji zaimplentowanych w bibliotece &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt;): --&amp;gt;&lt;br /&gt;
*położenie środka równowagi COP (''center of posture'')&lt;br /&gt;
*maksymalne przemieszczenie względem położenia środka równowagi (w AP,ML oraz przestrzeni AP/ML),&lt;br /&gt;
*długość drogi względem położenia środka równowagi (w AP,ML oraz przestrzeni AP/ML),&lt;br /&gt;
*średnia prędkość przemieszczenia (w AP,ML oraz przestrzeni AP/ML),&lt;br /&gt;
*wskaźnik Romberga - stosunek różnicy długości drogi przy oczach zamkniętych i otwartych, do sumy długości drogi przy oczach zamkniętych i otwartych&lt;br /&gt;
&amp;lt;!--*95% powierzchnia ufności elipsy - powierzchnia elipsy, w której powinno zawierać się około 95% punktów drogi COP,&lt;br /&gt;
*RMS (''root mean square'') (w AP i ML).---&amp;gt;&lt;br /&gt;
Dokładny opis matematyczny wyżej wymienionych wskaźników znajduje się w pracy (Prieto, 1996). &lt;br /&gt;
&lt;br /&gt;
Należy również przedstawić na wykresie przebieg ruchu COP oddzielnie w płaszczyźnie AP, ML oraz w przestrzeni AP/ML.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo studenci mają za zadanie przeprowadzić analizę rozkładu przestrzennego punktów statokinezjogramu. Statokinezjogramem lub posturogramem nazywamy wędrówkę COP w dwuwymiarowej płaszczyźnie podparcia. Kierunki na tej płaszczyźnie określa się jako AP (y) lub ML (x), przy czym ML oznacza wychylenia w płaszczyźnie czołowej (''medio-lateral''), a AP w płaszczyźnie strzałkowej (''anterio-posterior''). W celu przeprowadzenie takiej analizy, cały zakres zostaje podzielony na jednakowe komórki. Następnie obliczony zostaje histogram przestrzenny czasu przebywania w każdej z nich. Taki histogram pozwala ocenić, czy kontrola położenia referencyjnego COG (''center of gravity''), a tym samym pionowa orientacja ciała, jest prawidłowa. Wyznacznikiem prawidłowej kontroli jest histogram o skupionym rozkładzie i z wyraźnym maksimum. Upośledzenie kontroli objawia się tym, że histogram przestrzenny staje się rozmyty lub wyraźnie niesymetryczny (Błaszczyk, 2004).&lt;br /&gt;
&lt;br /&gt;
===Analiza danych: wychylenia dynamiczne===&lt;br /&gt;
&lt;br /&gt;
Oprócz wskaźników statycznych stabilności do oceny kontroli posturalnej wykorzystuje się również miary dynamiczne. Z punktu widzenia miar bezpośrednich, istotna jest ocena kontroli środka ciężkości ciała w czasie jego świadomego przemieszczania w wyznaczonym kierunku. W ramach pomiarów, studenci mieli za zadanie wykonać dwa rodzaje wychyleń (szybkie i &amp;quot;z przytrzymaniem&amp;quot;) w dwóch warunkach: bez informacji zwrotnej dla badanego oraz z informacją zwrotną dla badanego. Dla każdego z przypadków należy wyznaczyć następujące parametry:&lt;br /&gt;
&lt;br /&gt;
*położenie środka równowagi (dla warunku bez informacji zwrotnej będzie to COP ze stania swobodnego z oczami otwartymi, natomiast dla warunku z informacją zwrotną będzie to COP z sesji kalibracyjnej)&lt;br /&gt;
*wartość maksymalnego wychylenia (w określonym kierunku) względem położenia równowagi,&lt;br /&gt;
*wykresy składowych wychwiań względem położenia równowagi w płaszczyźnie AP, ML w zależności od czasu oraz wypadkowa trajektoria przemieszczeń COP (w dwuwymiarowej przestrzeni AP, ML).&lt;br /&gt;
&lt;br /&gt;
i zbadać czy informacja zwrotna wpływa na rezultaty badanego.&lt;br /&gt;
&lt;br /&gt;
Literatura:&lt;br /&gt;
*Błaszczyk J., Biomechanika kliniczna, PZWL, 2004&lt;br /&gt;
*Prieto T.E. et al., Measures of postural steadiness: differences between healthy young and elderly adults, IEEE Trans Biomed Eng, 1996, 43(9):956-66&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Przykładowe skrypty do analizy:&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;stanie swobodne&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
from obci.analysis.balance.wii_analysis import *&lt;br /&gt;
&lt;br /&gt;
import matplotlib.pyplot as py&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '~/' #full path&lt;br /&gt;
FILE_NAME = 'wii_baseline_2015-03-03_20-51-48' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
&lt;br /&gt;
    #add two additional (x, y) channels (computed from sensor values)&lt;br /&gt;
    wbb_mgr.get_x()&lt;br /&gt;
    wbb_mgr.get_y()&lt;br /&gt;
&lt;br /&gt;
    #estimate true sampling frequency value&lt;br /&gt;
    fs = analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS'))&lt;br /&gt;
    wbb_mgr.mgr.set_param('sampling_frequency', analysis_baseline.estimate_fs(wbb_mgr.mgr.get_channel_samples('TSS')))&lt;br /&gt;
&lt;br /&gt;
    #preprocessing&lt;br /&gt;
    wbb_mgr = wii_downsample_signal(wbb_mgr, factor=2, pre_filter=True, use_filtfilt=True)&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from standing task with eyes open&lt;br /&gt;
    smart_tags = wii_cut_fragments(wbb_mgr, start_tag_name='ss_start', end_tags_names=['ss_stop'])&lt;br /&gt;
    sm_x = smart_tags[0].get_channel_samples('x')&lt;br /&gt;
    sm_y = smart_tags[0].get_channel_samples('y')&lt;br /&gt;
    py.figure()&lt;br /&gt;
    print(wii_COP_path(wbb_mgr, sm_x, sm_y, plot=True))&lt;br /&gt;
    py.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia bez informacji zwrotnej&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_LEFT = '' #full path&lt;br /&gt;
FILE_NAME_LEFT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_RIGHT = '' #full path&lt;br /&gt;
FILE_NAME_RIGHT = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_DOWN = '' #full path&lt;br /&gt;
FILE_NAME_DOWN = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH_UP = '' #full path&lt;br /&gt;
FILE_NAME_UP = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'obci'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    #load data from right sway task&lt;br /&gt;
    wbb_mgr_right = read_file(FILE_PATH_RIGHT, FILE_NAME_RIGHT)&lt;br /&gt;
&lt;br /&gt;
    #here should be preprocessing... &lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway task (right)&lt;br /&gt;
    smart_tags_quick = wii_cut_fragments(wbb_mgr_right, start_tag_name='szybkie_start', end_tags_names=['szybkie_stop'])&lt;br /&gt;
    x_fragments_quick = [i.get_channel_samples('x') for i in smart_tags_quick]&lt;br /&gt;
    y_fragments_quick = [i.get_channel_samples('y') for i in smart_tags_quick]&lt;br /&gt;
&lt;br /&gt;
    #extract fragments from sway&amp;amp;stay task (right)&lt;br /&gt;
    smart_tags_long = wii_cut_fragments(wbb_mgr_right, start_tag_name='start', end_tags_names=['stop'])&lt;br /&gt;
    x_fragments_long = [i.get_channel_samples('x') for i in smart_tags_long]&lt;br /&gt;
    y_fragments_long = [i.get_channel_samples('y') for i in smart_tags_long]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*zadanie &amp;quot;wychylenia z informacją zwrotną&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from obci.analysis.balance.wii_read_manager import WBBReadManager&lt;br /&gt;
from obci.analysis.balance.wii_preprocessing import *&lt;br /&gt;
&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_baseline&lt;br /&gt;
from obci.exps.ventures.analysis import analysis_helper&lt;br /&gt;
&lt;br /&gt;
from obci.acquisition import acquisition_helper&lt;br /&gt;
&lt;br /&gt;
BASELINE_FILE_PATH = '' #full path&lt;br /&gt;
BASELINE_FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
FILE_PATH = '' #full path&lt;br /&gt;
FILE_NAME = '' #file name without extension&lt;br /&gt;
&lt;br /&gt;
def get_baseline_points(file_path, file_name):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot; baseline area is a rectangle with parameters:&lt;br /&gt;
        center point: xc, yc,&lt;br /&gt;
        width:        2*xa,&lt;br /&gt;
        height:       2*yb.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    xa, ya, xb, yb, xc, yc  = analysis_baseline.calculate(file_path, file_name, show=False)&lt;br /&gt;
    return xa, ya, xb, yb, xc, yc&lt;br /&gt;
&lt;br /&gt;
def read_file(file_path, file_name, tag_format = 'game'):&lt;br /&gt;
    file_name = acquisition_helper.get_file_path(file_path, file_name)&lt;br /&gt;
    wbb_mgr = WBBReadManager(file_name+'.obci.xml', file_name+'.obci.raw', file_name + '.' + tag_format + '.tag')&lt;br /&gt;
    return wbb_mgr&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    xa, ya, xb, yb, xc, yc = get_baseline_points(BASELINE_FILE_PATH, BASELINE_FILE_NAME)&lt;br /&gt;
    wbb_mgr = read_file(FILE_PATH, FILE_NAME)&lt;br /&gt;
    wbb_mgr.mgr = analysis_helper.set_first_timestamp(wbb_mgr.mgr) #adjusting tags to signal&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moduł &amp;lt;tt&amp;gt;obci.analysis.balance.wii_analysis&amp;lt;/tt&amp;gt; umożliwia wyznaczenie podstawowych wskaźników posturograficznych z zadania eksperymentalnego &amp;quot;stanie swobodne&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Maksymalna wartość wychwiań w AP i ML&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# max_sway  - maksymalne wychwianie (float),&lt;br /&gt;
# max_AP    - maksymalne wychwianie w kierunku AP (float), &lt;br /&gt;
# max_ML    - maksymalne wychwianie w kierunku ML (float).&lt;br /&gt;
&lt;br /&gt;
max_sway, max_AP, max_ML = wii_max_sway_AP_MP(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia wartość wychwiań COP od punktu (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# cop         - średnią wartość wychwiań do punktu (0, 0) (float),&lt;br /&gt;
# mean_y_COP  - średnią wartość wychwiań do punktu (0, 0) w AP (float),&lt;br /&gt;
# mean_x_COP  - średnią wartość wychwiań do punktu (0, 0) w  ML (float).&lt;br /&gt;
&lt;br /&gt;
mean_COP, mean_y_COP, mean_x_COP = wii_mean_COP_sway_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Długość drogi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# path_length    - długość drogi COP (float),&lt;br /&gt;
# path_length_x  - długość drogi COP w ML (float),&lt;br /&gt;
# path_length_y  - długość drogi COP w AP (float).&lt;br /&gt;
&lt;br /&gt;
path_length, path_length_x, path_length_y = wii_COP_path(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*RMS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# RMS     - (float),&lt;br /&gt;
# RMS_AP  - (float),&lt;br /&gt;
# RMS_ML  - (float).&lt;br /&gt;
&lt;br /&gt;
RMS, RMS_AP, RMS_ML = wii_RMS_AP_ML(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*95% powierzchnia ufności elipsy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# x  - macierz reprezentująca kanał x,&lt;br /&gt;
# y  - macierz reprezentująca kanał y.&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# e  - 95% powierzchnia ufności elipsy (float).&lt;br /&gt;
&lt;br /&gt;
e = wii_confidence_ellipse_area(x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Średnia prędkość przemieszczenia&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy WBBReadManager&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie).&lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# mean_velocity - średnia prędkość przemieszczenia,&lt;br /&gt;
# velocity_AP   - średnia prędkość przemieszczenia w AP,&lt;br /&gt;
# velocity_ML   - średnia prędkość przemieszczenia w ML.&lt;br /&gt;
&lt;br /&gt;
mean_velocity, velocity_AP, velocity_ML = wii_mean_velocity(wbb_mgr, x, y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Procentowa wartość przebywania w czterech ćwiartkach układu współrzędnych&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
# Parametry wejściowe:&lt;br /&gt;
# wbb_mgr  - obiekt klasy  WBBReadManager,&lt;br /&gt;
# x        - macierz reprezentująca kanał x,&lt;br /&gt;
# y        - macierz reprezentująca kanał y,&lt;br /&gt;
# plot     - True/False (opcjonalnie). &lt;br /&gt;
&lt;br /&gt;
# Funkcja zwraca:&lt;br /&gt;
# top_right     - procentowa wartość przebywania w prawej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# top_left      - procentowa wartość przebywania w lewej górnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_right  - procentowa wartość przebywania w prawej dolnej ćwiartce układu współrzędnych (float),&lt;br /&gt;
# bottom_left   - procentowa wartość przebywania w lewej dolnej ćwiartce układu współrzędnych (float).&lt;br /&gt;
&lt;br /&gt;
top_right, top_left, bottom_right, bottom_left = wii_get_percentages_values(wbb_mgr, x, y, plot=False)&lt;br /&gt;
&amp;lt;/source&amp;gt; --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Gbernatowicz</name></author>
		
	</entry>
</feed>