2013-01-17

Sygnały analogowe/cyfrowe. Potencjometr.


Sygnały analogowe i cyfrowe.

W świecie elektroniki powszechnie mamy do czynienia z sygnałami analogowymi i cyfrowymi. W internecie oczywiście możemy znaleźć masę informacji na ten temat. Ja tylko napiszę pokrótce, że sygnał cyfrowy przyjmuje wartość typu HIGH lub LOW, 1 lub 0, włączony lub wyłączony - czyli są 2 rodzaje wartości i nic pomiędzy nimi. Natomiast analogowe sygnały mogą przyjmować dowolną wartość w wybranym zakresie.
Przykładem (cyfrowym) jest tu np włącznik światła (który jest włączony lub wyłączony), czy np pokrętło głośności w radio (analogowy). Dobry do wyjaśnień jest również wspomniany już tu kiedyś kontroler PS3, który ma przyciski działające z sygnałem cyfrowym (wciśnięty, niewciśnięty), czy też analogową gałkę - mogącą przyjąć różne wartości.


Które są lepsze/bardziej przydatne? Oczywiście zależy od zastosowań.

Dlaczego o tym wspominam?
Do tej pory mieliśmy tu do czynienia z elementami cyfrowymi. I było to stosunkowo proste. Raspberry Pi samodzielnie nie potrafi jednak w żaden sposób "zrozumieć" sygnałów analogowych.  A co - jeśli będziemy chcieli (musieli) wykorzystać "coś" analogowego? (a nie chcemy korzystać np. z Arduino)

Wtedy przyda się nam dekoder analogowo - cyfrowy i właśnie tym się zajmiemy w tym poście.

Ja zakupiłem model PCF8591P. Koszt to niecałe 12zł.

Dane techniczne.

PCF8591P - Przetwornik A/C i C/A 8-bit DIP16

  •  Zasilanie: 2.5V - 6V
  •  Interfejs: I2C
  •  Obudowa: DIP16


Dokładniejsza dokumentacja TUTAJ

Opis slotów:





Przetwornik jest 8-bitowy, więc maksymalna wartość to 255. 

Zakupiłem też potencjometr obrotowy, który jest dobrym generatorem sygnałów analogowych :) Wraz z nakładką kosztował niecałe 2 zł. 

Dane techniczne.

Potencjometr obrotowy 10K:

  • Długość osi: 15mm
  • Średnica osi: 6mm
  • Kąt obrotu: 300°
  • charakterystyka: liniowa
  • tolerancja: +/- 20%
  • moc: 0,125W
  • temp. pracy: -10°C ÷ +70°C






Układ

potencjometr:
środkowy pin to OUT - czyli podłączamy do dekodera (tu mała uwaga - niektóre potencjometry mają dwie nóżki po jednej stronie i jedną nóżkę po drugiej stronie - wtedy "samotna" to OUT)

lewy pin do GND

prawy pin do 5V



dekoder:

AIN1 - analog input 1 - tu podłączamy środkowy pin potencjometru

AIN2 , 3, 4 - możemy podłączyć inne analogowe urządzenia - teraz nieużywane, więc do GND

A0-A2 - hardware address - też GND

VSS - negative supply - czyli też GND

Vdd - +5V

Aout - nie używany (nie podłączamy nigdzie)
Vref - + 5V
Agnd - analog ground - oczywiście GND
EXT - GND
OSC - nie używany (nie podłączamy nigdzie)
SCL - clock line - pin 5 w RPI GPIO 1 (I2C SCL)
SDA - data line - pin 3 w RPI GPIO 0 (I2C SDA)






Następnie musimy załadować odpowiednie moduły. W standardzie Raspbiana potrzebne nam moduły są "banowane", czyli nie można ich załadować. Tak więc edytujemy plik:
/etc/modprobe.d/raspi-blacklist.conf

i hashujemy:

#blacklist spi-bcm2708
#blacklist i2c-bcm2708

Następnie ładujemy moduły:
sudo modprobe spi-bcm2708
sudo modprobe i2c-bcm2708
sudo modprobe i2c-dev

W dmesg powinno pojawić się coś w tym stylu:

[270822.607823] bcm2708_spi bcm2708_spi.0: SPI Controller at 0x20204000 (irq 80)
[270828.657896] bcm2708_i2c bcm2708_i2c.0: BSC0 Controller at 0x20205000 (irq 79) (baudrate 100k)
[270828.658130] bcm2708_i2c bcm2708_i2c.1: BSC1 Controller at 0x20804000 (irq 79) (baudrate 100k)
[270875.242767] i2c /dev entries driver

Powinny pojawić się też 2 nowe urządzenia:
crw------- 1 root root 89, 0 Jan 14 23:32 /dev/i2c-0
crw------- 1 root root 89, 1 Jan 14 23:32 /dev/i2c-1

Kolejnym krokiem jest instalacja pakietów:
apt-get install python-smbus i2c-tools

I możemy przetestować czy wszystko jest w porządku. Sprawdzanie wykrycia urządzenia:

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

czy też sprawdzenie aktualnej wartości (na potencjometrze)
# i2cget -y 1 0x48
0x4c

Kod

Tu skorzystałem z zasobów forum LINK i pracy Grumpy Mike-a. Pozdrowienia :) Jako że dekoder pracuje przez interfejs i2c - kod wygląda nieco inaczej niż w poprzednich przypadkach.

#Read a value from analogue input 0
#in A/D in the PCF8591P @ address 0x48
from smbus import SMBus
import time

bus = SMBus(1)

print("Read the A/D")
print("Ctrl C to stop")
bus.write_byte(0x48, 0) # set control register to read channel 0
last_reading =-1

while(0 == 0): # do forever
   reading = bus.read_byte(0x48) # read A/D
   
   if(abs(last_reading - reading) > 2):
      print(last_reading - reading)
      last_reading = reading


2013-01-11

Czujnik odległości

Kolejnym moim testem jest ultradźwiękowy czujnik odległości - model HC - SR04.




Dane techniczne:

  • Zasilanie: DC 5 V
  • Częstotliwość: 40Hz
  • Max zasięg: 4m
  • Min zasięg: 2cm
  • Kąt działania: 15º 
  • Wymiary: 45*20*15mm
  • Waga: 90 gr
Dokumentacja TUTAJ, koszt takiego urządzenia to około 3 euro. Jak być może widać na rysunku czujnik posiada 4 piny: 5V, OUTPUT, TRIGGER, GND.


Sposób działania:

W stanie nieaktywnym na pinie OUTPUT jest zawsze 0V. Żeby aktywować czujnik (czyli, żeby wygenerowany został impuls ultradźwiękowy - a dokładniej 8 takich impulsów) wysyłany jest sygnał (co najmniej 10us) na port TRIGGER. Na porcie OUTPUT pojawia się wtedy stan wysoki (+5V) i pozostaje on w tym stanie dopóki sygnał ultradźwiękowy nie powróci do czujnika (czyli po odbiciu się od badanego obiektu). Żeby wyznaczyć odległość musimy zmierzyć ten czas, wziąść pod uwagę prędkość dźwięku i podzielić na 2 (bo droga jest do obiektu i z powrotem).
Tu niestety należy zwrócić uwagę na spore ograniczenie tego zestawu - czyli dużą niedokładność mierzenia czasu na RPI/Linuxie... Tak naprawdę powinniśmy zastosować dodatkowy hardware (albo wykorzystać np. Arduino), zapewniający nam dokładniejsze wyliczenia czasu. Dla zainteresowanych szczegółami proponuje poszukać zagadnienia "non realtime os".


OSTRZEŻENIE !
Przy podłączaniu wszelkich kabelków należy zachować ostrożność, gdyż może zakończyć się to uszkodzeniem sprzętu lub uszczerbkiem na zdrowiu. Robisz to na własną odpowiedzialność.


Układ:

Od razu zaznaczę, że tym razem znalazłem gotowe rozwiązanie i niezbyt wysilałem się intelektualnie. Za układ i kod możemy podziękować autorowi tej strony:

Jak możemy wyczytać na powyższej stronce - problemem tego czujnika (w przypadku współpracy z Malinką) jest fakt, że pracuje z napięciem 5V. Jak już wiemy (np. STĄD) porty GPIO mogą pracować z napięciem 3.3V, więc musimy wykorzystać prostą sztuczkę z rezystorami.

tak więc układ:

+5V - pin 2 w RPI
GND -  pin 6 w RPI
Trigger - GPIO 23
Echo - rezystor 330 Ω (lub 1K) -> GPIO 24 -> rezystor 470 Ω (lub 1K5) -> GND

Źródło: raspberrypi-spy.co.uk

wartości rezystorów mogą być oczywiście inne - tak jak zaleca autor - muszą spełniać zależność :
R1 < R2 < 2*R1

Przydałoby się jednak kupić kolorowe kabelki ;)

Kod:

kod wrzucam również w oryginale (szacunek dla autora), mimo, że ja go nieco zmodyfikowałem (np. wrzuciłem pętle, żeby odległość sprawdzana była co parę sekund - w ten sposób wygodniej mi było testować ;) ).

#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# ultrasonic_1.py
# Measure distance using an ultrasonic module
#
# Author : Matt Hawkins
# Date   : 09/01/2013

# Import required Python libraries
import time
import RPi.GPIO as GPIO

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO = 24

print "Ultrasonic Measurement"

# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Allow module to settle
time.sleep(0.5)

# Send 10us pulse to trigger
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start = time.time()

while GPIO.input(GPIO_ECHO)==0:
  start = time.time()

while GPIO.input(GPIO_ECHO)==1:
  stop = time.time()

# Calculate pulse length
elapsed = stop-start

# Distance pulse travelled in that time is time
# multiplied by the speed of sound (cm/s)
distance = elapsed * 34300

# That was the distance there and back so halve the value
distance = distance / 2

print "Distance : %.1f" % distance

# Reset GPIO settings
GPIO.cleanup()

A to mój profesjonalny zestaw do badań skuteczności czujnika ;) czyli pusta przestrzeń, miarka oraz ciemny przedmiot z prostym kształtem. 



Wg moich badań precyzja jest naprawdę dobra. Powtarzalność wyników jest bardzo dobra (nie skacze np o parę centymetrów), dokładność również całkiem niezła. Dla prostych zastosowań zdecydowanie wystarczająca.  
Zbadałem też układ z innymi przedmiotami i wyniki również są obiecujące. Ultradźwięk to jednak dobra opcja.

Podsumowując, mimo swoich ograniczeń czujnik + RPI to ciekawy zestaw. Jeśli w naszym projekcie niezbędna jest duża precyzja to zapewne warto poszukać innego rozwiązania, jeśli możemy przymknąć na to nieco oko - zdecydowanie polecam.

To już chyba mój ostatni czujnik na tą chwilę. Pora się zabrać za jakiś konkretny projekt. Mam pomysł (mam nadzieję, że starczy mi chęci i umiejętności) - ale do jego realizacji jeszcze dłuuuuga droga. W międzyczasie będę starał się wrzucać kolejne posty dotyczące RPI.    

2013-01-10

Tunelowanie ssh

Ten post znów nie jest związany z Raspberry, traktuję to raczej jako notatkę.
Miałem ostatnio potrzebę zalogowania się do domowego routera z zewnątrz (z internetu). Ze względów bezpieczeństwa zablokowałem taką możliwość na routerze (możliwy jest dostęp tylko z sieci wewnętrznej).
Co więc mogę zrobić? 
Jak już wspomniałem TUTAJ mam możliwość dostania się bezpośrednio do mojej Malinki w sieci domowej. Tak więc postanowiłem wykorzystać tunel ssh, żeby udostępnić sobie (szyfrowany) dostęp do domowego routera. 
Wykonujemy więc prostą komendę:
ssh -L 9999:192.168.1.1:80 pi@mojhost.no-ip.org
gdzie:
9999 - to dowolny port, który będziemy używać lokalnie (czyli na komputerze w sieci zewnętrznej)
192.168.1.1 - czyli adres routera domowego (widziany z sieci domowej)
80 - port na którym nasłuchuje router (może być 80, może być 443)
mojhost.no-ip.org - czyli publiczny adres naszego hosta, zamiast nazwy może być po prostu publiczny adres IP

Pozostaje nam wpisać w przeglądarce:
http://localhost:9999
i dostaliśmy się do domowego routera.

Przy okazji tylko wspomnę, że możemy ssh wykorzystać również jako proxy. Czyli łącząc się w ten sposób:
ssh ZDALNY_KOMPUTER -D 8080
mamy lokalne proxy na porcie 8080, które przedstawi nas w świecie IP z adresem publicznym naszego ZDALNEGO_KOMPUTERA zamiast z naszym. 
Czyli np ustawiamy w naszej ulubionej przeglądarce internetowej proxy na localhost:8080 w polu SOCKS Host i działa :)

Detektor ruchu/PIR

Następny na mojej liście testów jest detektor ruchu PIR (czyli Passive Infra-Red sensor).
Zakupiłem model  HC-SR501, kosztował niecałe 4euro.





Dane techniczne:
  • Zasięg: 3 - 7 m
  • Kąt: 110º
  • Napięcie wyjścia: 3.3V
  • Temperatura działania: -20℃ - +50℃
  • Wymiary: 32*24 mm

Po wykryciu ruchu sensor podaje 3,3 V (idealnie dla RPI) na wyjściu. 
Posiada 2 potencjometry: SENSITIVE i TIME oraz jeden jumper.
TIME - czas "podawania" napięcia na wyjściu - definiowalny od 3 do 18 sekund.
SENSITIVE - dystans, na którym czujnik ma wykrywać ruch (3-7metrów)
JUMPER - stan H - po wykryciu ruchu działanie czujnika jest wstrzymane (na czas zdefiniowany przez TIME)
JUMPER - stan L - czujnik działa cały czas


OSTRZEŻENIE !
Przy podłączaniu wszelkich kabelków należy zachować ostrożność, gdyż może zakończyć się to uszkodzeniem sprzętu lub uszczerbkiem na zdrowiu. Robisz to na własną odpowiedzialność.


Układ:

pin 5V - do portu 2 w RPI
pin OUT - do GPIO 23 w RPI
pin GND - wiadomo
(podłączyłem to kabelkami męsko - żeńskimi, gdyż nie ma zbytnio opcji wpięcia bezpośrednio do płytki stykowej)
no i dodałem jeszcze diodę - podłączoną tak samo jak TUTAJ






Po podłączeniu napisałem prosty skrypt - który przy wykryciu napięcia na porcie OUT zapali diodę.

import RPi.GPIO as GPIO
 
PIR = 23
LED = 14
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)
 
while True:
    if GPIO.input(PIR):
        GPIO.output(LED, True)          
    else:
        GPIO.output(LED, False)         

no i działa.

Przemyślenia. 
Po testach stwierdzam, że czujnik jest dość precyzyjny, jego czas reakcji jest bardzo szybki, tylko nie do końca podoba mi się fakt, że minimalny czas podawania napięcia po wykryciu ruchu jest tak długi (3 sekundy - choć i tak dobrze, że jest sterowany), no ale można to było wyczytać w dokumentacji ;)


Zastosowanie.
Naprawdę przeróżne. Można stworzyć nawet automatycznie otwierane drzwi, czy system wykrywania obecności domowników + zapalanie światła albo np dla miłośników przyrody - system wykrywania obecności ptaków w karmniku + zrobienie zdjęcia przez kamerkę :)

Jako ciekawostkę wrzucam tu filmik dotyczący detekcji ruchu - żebyśmy bli przygotowani na różne możliwości;) (nie do końca ma to związek z "naszym" rodzajem detektora ruchu ale ten program zawsze warto obejrzeć ;) )





2013-01-09

Odbiornik podczerwieni/LIRC

Kolejnym moim testem jest podłączenie odbiornika podczerwieni.

Zakupiłem odbiornik IR typu TSOP4838.

Źródło: vishay.com

Nie mam dokładnej dokumentacji, ale z tego co wyczytałem pracuje na częstotliwości 38kHz, ma duży zasięg (niby do 35m), odbiór sygnału pod kątem do 45° i co najważniejsze dobrze pracuje na 3.3V. Można go dostać dość łatwo, mnie kosztował ~3 zł. 

UPDATE: dokumentacja TUTAJ


OSTRZEŻENIE !
Przy podłączaniu wszelkich kabelków należy zachować ostrożność, gdyż może zakończyć się to uszkodzeniem sprzętu lub uszczerbkiem na zdrowiu. Robisz to na własną odpowiedzialność.


UKŁAD
Podłączenie jest banalne, pierwszy pin do GPIO18 (6 z prawej), drugi pin to GND, trzeci pin to 3.3V.  


Instalujemy:
apt-get install lirc
Ładujemy moduł:
modprobe lirc_rpi
w syslogu powinno pojawić się
Dec 31 16:29:04 raspberrypi kernel: [11871.816457] lirc_rpi: auto-detected active low receiver on GPIO pin 18
powinno pojawić się też urzadzenie
# ls -la /dev/lirc0
crw-rw---T 1 root video 250, 0 Dec 31 16:29 /dev/lirc0
następnie
mode2 -d /dev/lirc0
bierzemy pilota (dowolnego - może być od telewizora) i każde wciśnięcie klawisza powinno generować komunikaty pulse space z numerkami...

Coś w tym stylu:
space 17826
pulse 129
space 803
pulse 174
space 790
pulse 100
space 18114
pulse 183
space 806
pulse 205
space 775
pulse 157
space 18484
pulse 222
space 1516
Są to "kody", które odpowiadają wciśnięciu poszczególnych klawiszy. Zamysł jest więc taki, żeby wychwycić taki kod i po jego wystąpieniu wywołać konkretne zdarzenie.

Skorzystamy więc z demona lirc.
LIRC to bardzo ciekawy projekt. Wiele mówiący skrót  Linux Infrared remote control. Polecam poczytanie dokumentacji i możliwości.
Projekt oferuje masę gotowych konfigów - lista supportowanych pilotów:
http://lirc.sourceforge.net/remotes/

Ja gdzieś wygrzebałem bardzo stary pilot, więc wygeneruję sobie plik konfiguracyjny sam.
Najpierw przyda się znajomość dostępnych nazw poszczególnych klawiszy.
irrecord --list-namespace
następnie odpalamy (tu zmiana (lircd.conf) dzięki komentarzom - dzięki:) )
irrecord -d /dev/lirc0 ~/lircd.conf
czyli generator konfiguracji. Każe nam powciskać różne klawisze, po czym mamy gotowy plik z kodami raw dla każdego klawisza pilota.
np dla klawisza 1 w moim pilocie raw_code wygląda tak:
          
name KEY_1

             9096    4465     621     515     619     520

              601     512     625     519     585     546

              600     517     620     517     616     521

              598     516     625    1649     600    1662

              610    1632     623    1653     599    1655

              616    1634     631    1646     597     517

              625     512     595    1659     620     517

              617     521     597     520     627     510

              616     522     594    1655     595    1658

              619     520     616    1633     632    1644

              599    1654     618    1636     620    1654

              600

Kopiujemy wygenerowany plik do /etc/lirc. Następnie musimy przygotować kolejny plik:

# cat /etc/lirc/hardware.conf

# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false

#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false

#Try to load appropriate kernel modules
LOAD_MODULES=true

# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"

# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"

# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""
i możemy wystartować demon
/etc/init.d/lirc start
Weryfikujemy działanie przez komendę:
irw
przy wciśnięciu każdego zdefiniowanego klawisza powinna pojawić się jego nazwa:
0000000000000001 00 KEY_1 pilotMOJ
0000000000000002 00 KEY_2 pilotMOJ
0000000000000003 00 KEY_3 pilotMOJ
000000000000000b 00 KEY_OK pilotMOJ
Tak więc teraz możemy zmapować przycisk do dowolnej komendy. Tworzymy w katalogu domowym plik .lircrc i umieszczamy w nim definicję:
# cat ~/.lircrc
begin
 prog = irexec
 button = KEY_1
 config = echo "Klawisz '1' wcisniety!"
end
uruchamiamy 
irexec
i wciskamy na pilocie przycisk 1, powinno się pojawić
Klawisz '1' wcisniety!
Inna opcja. Tworzymy skrypt, upewniamy się, że jest uruchamialny lub korzystamy z już utworzonego. Ja np po wciśnięciu OK chce mieć wyświetloną temperaturę na dworzu. Korzystam ze skryptu opisanego TUTAJ i dodaję:
begin
 prog = irexec
 button = KEY_OK
 config = echo "Temperatura w tym momencie:"; /projekty/temperatura/getTemp.sh
end

Możemy uruchomić irexec jako demon poprzez:
irexec -d

i aplikacja będzie działać na stałe w tle.

Dokumentacja z parametrami TUTAJ
Warto zwrócić uwagę na parametr repeat - czyli co się stanie jeśli drugi raz wciśniemy dany przycisk. Nieraz nie chcemy przecież, żeby dana aplikacja odpaliła się raz jeszcze, ale np chcemy żeby okno zrobiło się aktywne (np. wyskoczyło okno wcześniej zminimalizowane). Ogólnie jest to dość potężny projekt, więc da się z nim dużo zrobić.

No to teraz ogranicza nas już tylko wyobraźnia. Możemy podpiąć dowolną aplikację pod dowolny przycisk w pilocie i sterować różnymi zdarzeniami (np. uruchomienie XBMC, przeglądarki, wyłączenie systemu, zapalenie diody itp).

Jeszcze tylko dodam, że istnieje projekt umożliwiający współpracę z python-em. Więcej szczegółów http://pylirc.mccabe.nu/

Jest nawet w repozytorium Raspbian-a, więc można go zainstalować:
apt-get install python-pylirc

Inne zastosowanie. 
Np jeśli mamy problemy z libcec, a chcemy korzystać z pilota w XBMC (wspomniane TUTAJ), możemy podpiąć odbiornik i korzystać z dobrodziejstw pilota (jako, że sposób podłączenia jest banalny możemy to zrobić nawet bez płytki stykowej). Oczywiście nie musimy ograniczać się do XBMC - możemy wykorzystać pilota do innych aplikacji. Masa aplikacji multimedialnych ma gotowe konfigi dla pilotów.
Poza tym możemy podpiąć się do wielu domowych urządzeń (np. lampka nocna), czy całe systemy "home automation" i sterować nimi za pomocą zwykłego pilota. Tu prawie nie ma ograniczeń (aczkolwiek zazwyczaj przydaje się już nieco bardziej zaawansowana wiedza z zakresu elektroniki).