Raspberry - Paweł Szabaciuk

Paweł Szabaciuk

Software Developer

Category: Raspberry

Monitoring środowiska w domu – wersja działająca

W końcu (w połowie sierpnia :p) udało mi się uruchomić system do monitoringu danych środowiskowych.
Koncepcja w stosunku do pierwotnej trochę się zmieniła, przez co centralką zbierającą i przechowującą dane jest Raspberry Pi.
Hosting zapewnia NodeJS wraz z ExpressJS. Dane zbierane są do bazy danych SQLite.
Całość chodzi stabilnie od prawie miesiąca.
Czujniki się nie zmieniły (chociaż kolejna wersja będzie poprawiona, antena wzdłuż baterii, czujnik od strony baterii a nie procesora).
Do RPi podpięty jest wygrzebany z otchłani śmieci na biurku wyświetlacz OLEDowy. Wyświetla bieżące dane.

Poniżej kilka screenów z hostingu:

WiringPi (like) obsługa przerwań

Dzisiaj zajmę się poprawną obsługą oczekiwania na przerwanie, jeśli przerwania oparte są na poll (czyli biblioteka WiringPi i klony).
W czym jest problem?
Otóż poll chodzi sobie w drugim wątku. Jest to metoda nie obciążająca procesora. Samo poll nie zużywa mocy obliczeniowej. Natomiast większość przykładów, które widziałem, oparte są na pętli nieskończonej, oczekującej na wystąpienie przerwania. Co powoduje, że ta pętla obciąża nam procesor w 100%.
Przykład takiego użycia:

 C++ | 
 
 copy code |
?

01
bool packetAvailable = false;         
02
 
03
void signalsInterrupt(void) 
04
{
05
	packetAvailable = true;
06
}
07
 
08
int main(int argc, char *argv[])
09
{
10
	wiringPiSetup();
11
 
12
	pinMode(GDO2, INPUT);
13
	pullUpDnControl(GDO2, PUD_UP);
14
 
15
	wiringPiISR(GDO2, INT_EDGE_FALLING, &signalsInterrupt);
16
 
17
	while (1)
18
	{
19
		if (packetAvailable) 
20
		{
21
			(...)
22
		}
23
	}
24
 
25
	return 0;
26
}

Mało eleganckie, nieprawdaż?
Z pomocą przychodzą nam mechanizmy do obsługi wątków, jak np. semafory.
A oto poprawny przykład, zużywający ~0% procesora:

 C++ | 
 
 copy code |
?

01
static sem_t interrupt;
02
 
03
void signalsInterrupt(void) 
04
{
05
	sem_post(&interrupt);
06
}
07
 
08
int main(int argc, char *argv[])
09
{
10
	wiringPiSetup();
11
 
12
	pinMode(GDO2, INPUT);
13
	pullUpDnControl(GDO2, PUD_UP);
14
 
15
	sem_init(&interrupt, 0, 0);
16
	wiringPiISR(GDO2, INT_EDGE_FALLING, &signalsInterrupt);
17
 
18
	while (1)
19
	{
20
		sem_wait(&interrupt);
21
 
22
		(...)
23
	}
24
 
25
	return 0;
26
}

Kod działa następująco. sem_init definiuje nam semafor obsługujący przerwanie. Callback signalsInterrupt wywoływany jest przez wątek obsługujący przerwanie (ten z poll). Tutaj ustawiany jest semafor. W pętli głównej while(1) oczekujemy na ustawienie semafora. Wszystko bez zużycia procesora.

GPS dla Raspberry

Do celów testowych dostałem moduły GPS NEO-6M. Jest to kompletny moduł GPS gadający po UART, posiadający wbudowaną ( e tam, naklejoną na płytkę 🙂 ) antenę ceramiczną.

Połączenie między RPi a modułem GPS wykonujemy wg: schematu:

Aby zaprząc GPS do pracy, musimy na początek wyłączyć konsolę na UART
Continue reading

Zdalny katalog z Raspberry PI pod Windows

Ponieważ ostatnio tworze dużo prostych programów oraz przymierzam się pomału do klienta webowego, pomyślałem sobie, że przydało by się zamontować katalog domowy z RaspberryPi pod Windows. Kopiowanie przez SCP jest przyjemne, ale w takim użytku jak potrzebuję obecnie nie do końca wygodne.
Continue reading

RaspberryPi 2 OpenCV 3.1.0

Pracując nad obecnym projektem pojawiła się potrzeba detekcji obiektów widzianych przez kamerę. Po dość krótkich poszukiwaniach znalazłem ciekawą propozycję: OpenCV. Jest to biblioteka do przetwarzania obrazu. Ma szeroki wachlarz wbudowanych funkcjonalności. Przykładowo: możemy dosłownie przy użyciu jednej linijki rozpoznać gdzie na zdjęciu są twarze.
Same opisy współpracy z RPi są dość stare i dotyczą głównie wersji dostępnej z repozytoriów (2.4) z wykorzystaniem Pythona. Nie lubię (nie znam :)) tego języka, więc postanowiłem wykorzystać natywne możliwości OpenCV czyli C++.

Przed rozpoczęciem budowania biblioteki musimy poinstalować trochę pakietów:

 Bash | 
 
 copy code |
?

1
sudo apt-get install build-essential
2
sudo apt-get install cmake cmake-curses-gui git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev checkinstall
3
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
4

Jeśli chcemy mieć możliwość używania OCR:
 Bash | 
 
 copy code |
?

1
sudo apt-get install tesseract-ocr tesseract-ocr-eng tesseract-ocr-pol libtesseract-dev

Teraz ściągamy kod źródłowy bierzącej wersji OpenCV oraz biblioteki Contrib:

 Bash | 
 
 copy code |
?

1
git clone https://github.com/Itseez/opencv.git
2
git clone https://github.com/Itseez/opencv_contrib.git

Wchodzimy do katalogu ze źródłami opencv:

 Bash | 
 
 copy code |
?

1
cd ~/opencv

Tworzymy katalog w którym odbywać się będzie kompilacja:
 Bash | 
 
 copy code |
?

1
mkdir release
2
cd release

Konfigurujemy budowanie:
 Bash | 
 
 copy code |
?

1
ccmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D WITH_V4L=ON -D WITH_OPENGL=ON ..

Ustawiamy ścieżkę do biblioteki Contrib:
 Bash | 
 
 copy code |
?

1
OPENCV_EXTRA_MODULES_PATH ../opencv_contrib

Włączamy też w przypadku RPi2 NEON.
Ja wyłączyłem budowanie przykładów, testów, testów wydajności oraz dokumentacji.
Zapisujemy konfigurację i kompilujemy. Przy użyciu RPi2 oczywiście jest to polecenie:
 Bash | 
 
 copy code |
?

1
make -j4

Czekamy na zakończenie (pomyślne) kompilacji. Potrwa to kilka h.
Następnie utworzymy sobie paczkę instalacyjną:
 Bash | 
 
 copy code |
?

1
sudo checkinstall

I na koniec:
 Bash | 
 
 copy code |
?

1
sudo nano /etc/ld.so.conf.d/opencv.conf

Wstawiamy linijkę: /usr/local/lib
 Bash | 
 
 copy code |
?

1
sudo ldconfig

I mamy skompilowane i zainstalowane OpenCV.

Teraz musimy ściągnąć i zainstalować OpenCV Userland. Jest to zestaw bibliotek specjalnie pod RaspberryPI.

 Bash | 
 
 copy code |
?

1
git clone https://github.com/raspberrypi/userland.git

I tutaj postępujemy analogicznie jak wyżej, przy kompilacji OpenCV.

Do testów użyjemy kamery podłączonej do interfejsu kamery na RPi. W tym celu dodajemy moduł:

 Bash | 
 
 copy code |
?

1
sudo nano /etc/modules
2
bcm2835-v4l2

Żeby nie restartować systemu:
 Bash | 
 
 copy code |
?

1
modprobe bcm2835-v4l2

I to wszystko. Możemy używać kamery standardowym mechanizmem OpenCV.

Raspberry Pi RTC MCP7940M

Jedną z większych wad RPi jest brak wbudowanego układu RTC. Nie jest jednak problemem wyposażenie naszego komputerka w taki układ. Ilość układów RTC przyprawia o zawrót głowy. Ja niestety, w obecnym projekcie nie przemyślałem tego do końca i kupiłem tani i (wtedy) dostępny układ MCP7940M.
Dlaczego niestety? Ponieważ RTC w tej wersji nie posiada wsparcia dla podtrzymania bateryjnego i nie jest oficjalnie wspierany przez kernel linuxa (tak do dzisiaj myślałem).
Całkiem przypadkiem odkryłem, że jednak jest obsługiwany i nie wymaga żadnych przeróbek.

Schemat podłączenia układu jest dość klasyczny. Układ jest podtrzymywany przez baterię. Ważna uwaga, bateria musi mieć wyjściowo niższe napięcie niż szyna zasilania 3.3V. Aby to zapewnić, zastosowałem diodę Schottky’ego (D2), która ma mniejszy spadek napięcia niż zwykła dioda 1N4148 (D1). Tak naprawdę, to ważne jest to tylko jak mamy nową baterię. Stara na pewno będzie miała mniejsze napięcie niż szyna 3.3V i wtedy nie ma problemu.
Jeśli zasilimy układ z szyny 5V też nie będzie z tym problemu. Układ może być zasilany napięciem od 1.8V do 5.5V (Operating voltage range of 1.8V to 5.5V: nota katalogowa).
schemat-mcp9740m
Tak, wiem, na schemacie jest PCF8563P, nie chciało mi sie tworzyć nowego elementu w eagle, więc jest ten 🙂

Ustawienia samego RPi są banalnie proste.
Podłaczamy nasz RTC i sprawdzić czy wszystko z nim ok. Do tego instalujemy narzędzie do obsługi i2c:

 Bash | 
 
 copy code |
?

1
sudo apt-get install i2c-tools

I sprawdzamy czy nasz RTC jest dostępny (dla wersji rev.1 RPi zamieniamy 1 na 0):
 Bash | 
 
 copy code |
?

1
sudo i2cdetect -y 1

Powinniśmy mieć wpis dla adresu 6f:
 Bash | 
 
 copy code |
?

1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
2
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
3
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
4
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
5
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
6
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
7
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
8
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6f
9
70: -- -- -- -- -- -- -- 77

To jest adres układu MCP7940x. Dalej, właczamy moduły dla i2c oraz rtc-ds1307. Edytujemy plik /etc/modules, dodając w nim linie:
 Bash | 
 
 copy code |
?

1
i2c-dev
2
i2c-bcm2708
3
rtc-ds1307

Tak, dobrze napisałem, moduł rtc-ds1307. Potrafi on gadać nie tylko z tytułowym MCP7940, ale też z następującymi układami:

  • ds1307
  • ds1337
  • ds1338
  • ds1339
  • ds1388
  • ds1340
  • ds3231
  • m41t00
  • mcp7940x
  • mcp7941x
  • pt7c4338
  • rx8025

Dodajemy wpis do /etc/rc.local konfigurujący nam nasz układ RTC (dla rev.1 zamieniamy i2c-1 na i2c-0):

 Bash | 
 
 copy code |
?

1
echo mcp7940x 0x6f > /sys/class/i2c-adapter/i2c-1/new_device
2
Pierwszy wyraz po echo definiuje nam typ układu RTC (z powyżesz listy), drugi określa adres wcześniej odczytany.
Teraz wystarczy że zrestartujemy system i nasz RTC powinien być już aktywny:
 Bash | 
 
 copy code |
?

1
ls -l /dev | grep rtc

Powinniśmy dostać coś w stylu:
lrwxrwxrwx 1 root root 4 gru 30 17:09 rtc -> rtc0
crw——- 1 root root 254, 0 gru 30 17:09 rtc0
 Bash | 
 
 copy code |
?

1
lrwxrwxrwx 1 root root           4 gru 30 17:09 rtc -> rtc0
2
crw------- 1 root root    254,   0 gru 30 17:09 rtc0

Jeśli tak nie jest, to coś jest nie tak z naszym układem lub żle skonfigurowaliśmy RPi.

Za operacja na RTC odpowiada komenda hwclock. I tak, oby odczytać czas z RTC:

 Bash | 
 
 copy code |
?

1
sudo hwclock -r

Ustawienie RTC na podstawie aktualnego czasu systemowego:
 Bash | 
 
 copy code |
?

1
sudo hwclock -w

I odwrotnie, systemowy na podstawie RTC:
 Bash | 
 
 copy code |
?

1
sudo hwclock -s

Teraz możemy wyłączyć domyślnie włączony ntp, czyli synchronizacja czasu przez połączenie internetowe:

 Bash | 
 
 copy code |
?

1
2
sudo update-rc.d ntp disable
3
Dzięki temu, nasz system nie będzie się aktualizować za każdym razem przy uruchomieniu tylko korzystać z RTC.
Aby jednak czasem zsynchronizować nasz RTC z resztą świata, warto dopisać do crona wykonywanie polecenia np. raz na tydzień: ntpd -gq ; hwclock -w

© 2018 Paweł Szabaciuk

Theme by Anders NorenUp ↑