IQhome Kamera obrotowa

Kierując się przysłowiem "Potrzeba matką wynalazków" stworzyłem projekt, który może przydać się każdemu.

 

Głównym celem projektu było przesyłanie obrazu w czasie rzeczywistym i zbieranie danych z czujników. Oczywiście program w mojej głowie zaczął się rozwijać, więc dołożyłem także sterowanie urządzeniami za pomocą przekaźników oraz sterowanie kamerą. Docelowo projekt ma służyć jako kamera udostępniająca zawody sportowe za pomocą mobilnego internetu w celu popularyzacji mało popularnych sportów (w moim przypadku to ciężary :) ). Oczywiście projekt idealnie nadaje się także do podglądu swojego podwórka, żony, czy dziecka. Można używać go nawet jako stacja meteorologiczna lub alarm, ponieważ można podłączyć do niego termometry cyfrowe DS18B20, różnorakie czujniki takie jak kontraktrony, czujki ruchu gazu itp.

1) Co trzeba posiadać, aby projekt działał:

Aby odpalić projekt w podstawowej wersji będziecie potrzebować tylko Raspberry, karty SD (najlepiej cat. A), dostępu do internetu. Wszystko możecie znaleźć w popularnych sklepach internetowych:

Ja użyłem RPI wersje B:

http://botland.com.pl/moduly-glowne-i-zestawy-raspberry-pi/972-raspberry-pi-model-b-512mb-ram.html

Ale dostępna jest już tańsza i lepsza wersja z 4USB, 40 pinami i lepszą pamięcią RAM. Ja niestety takiej nie posiadam, więc program pisałem pod wersje B.

http://botland.com.pl/moduly-i-zestawy-raspberry-pi-/2543-raspberry-pi-model-bplus-512mb-ram.html

Następną ważną rzeczą jest karta SD kategorii 10. Szybkość na takiej karcie jest mocno zauważalna.

http://botland.com.pl/karty-pamieci/2124-karta-pamieci-goodram-sd-sdhc-8gb-klasa-10.html

Następną ważną rzeczą jest kupno odpowiedniej kamery. Dla RPI jest dedykowana kamera HD, która daje obraz w podczerwieni i można ją podłączyć do dedykowanej szyny. Oczywiście taka kamera kosztuje tyle co RPI, a ja za moją pensję nawet nie mogę samodzielnie wynająć kawalerki, dlatego wybór padł na zwykłą kamerkę internetową na USB Logitech za 30zł :). Oczywiście taka kamera ma swoje plusy, ponieważ obraz HD i tak nie nadawałby się do internetu. Jakoś 640x480 jest idealna do przesyłu danych z internetu mobilnego.

Te 3 rzeczy wystarczy, aby stworzyć monitoring. Ja oczywiście poszedłem o krok dalej i postanowiłem zapalać światło przez stronę internetową. Do tego macie do wyboru kilka modułów. Najtaniej i najłatwiej wychodzi kupić gotowy polutowany układ z gold pinami:

http://botland.com.pl/przekazniki/2579-czterokanalowy-modul-przekaznikow-rm6-z-izolacja-optoelektroniczna-5v-10a125vac.html

Taki układ będzie nas kosztował 30zł, a dzięki niemu będziemy mogli wysterować nocną lampkę, czy załączyć klimatyzator. Zauważyłem, że najlepszą frajdę sprawia sterowanie kamerą w czasie rzeczywistym za pomocą przycisków na stronie internetowej. Żeby tego dokonać będziemy musieli zakupić serwo mechanizmy ze stelażem. Dzięki takiemu układowi będziemy mogli obracać kamerą w dwóch płaszczyznach pion i poziom (niestety przekładnie za szybko się przemieszczają i nie da się płynnie działać), a wszystko będzie kosztowało nas jakieś 80zł + mostek H:

http://botland.com.pl/chwytaki-i-uchwyty/2176-uchwyt-do-serw-standard-pantilt-long-kit-serwa-dagu.html

Oczywiście, aby mostek H działał, należy zmodyfikować serwa, tu macie opis jak to zrobić:

http://www.forbot.pl/forum/topics20/mechanika-serwa-modelarskie-w-robotyce-amatorskiej-kompendium-vt3902.htm

Dobrze kupić gotowy moduł Mostka H, wtedy ni będziemy musieli się za dużo męczyć. Ja posiadam coś takiego:

http://electropark.pl/moduly-sterowniki-silnikow/2940-modul-podwojny-sterownik-silnika-l298-5901002940002.html

Na koniec została nam kwestia zasilania. Zasilacz dobieramy do własnych potrzeb, czyli jeśli chcemy sterować małymi mikro serwami na 5V, to dobrze kupić zasilać z dwoma wejściami USB. Wtedy silniki podepniemy do jednego USB, a RPI do drugiego:

http://botland.com.pl/zasilacze-sieciowe-5-v/2866-zasilacz-goobay-2x-usb-5v-41a-raspberry-pi.html

Należy patrzeć na wydajność prądową, bo może się okazać, że nasz zasilacz nie udźwignie pracy 2 silników i raspberry, w takim przypadku raspberry się nam zresetuje. Jeśli wybierzecie silniki na wyże napięcie, to najlepiej odseparować źródła zasilania silnik - logika. Czyli dać zasilanie na silniki i drugi zasilacz na RPI.

2) Jak to działa?

Idea działania jest następująca. Tworzymy w pamięci RAM pliki, które będą komunikowały się z serwerem i głównym programem wykonawczym napisanym w C. Jeśli chcemy załączyć jakieś piny na RPI wystarczy wysłać odpowiednie liczby do odpowiednich plików, a program główny, który odpalony jest jako ROOT przekształci te liczby i zapali lub zgasi odpowiednie piny.  Jeśli chcemy wyświetlić stan pinów na stronie, to wystarczy pobrać dane z plików i odświeżyć stronę. Oczywiście znając się troszkę na JavaScript i PHP można takie dane odświeżać w tle, bez odświeżania strony. To jest cała idea działania tej aplikacji.

3) KOD:

Ja napisałem kod, który jest w pętli nieskończonej i jest on odpalony jako administrator. Można także wywoływać programy napisane z C za pomocą strony internetowej tylko w określonych momentach, ale to wymaga konfiguracji praw dostępu itp. Można to znaleźć na stronie:

http://www.raspberry-projects.com/pi/software_utilities/phpapache

Dla przykładu. Aby sterować pinami za pomocą strony internetowej trzeba zmodyfikować prawa dostępu wpisując:

sudo visudo

I na końcu pliku dopisując:

www-data ALL=(ALL) NOPASSWD: ALL

W takim przypadku użytkownik www-data nie będzie wymagał hasła admina i będzie miał dostęp do pinów procesora.

Program główny w C:

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
#define PIFACE_BASE 0
 
int scanButton (int button,int liczba)
{
if (digitalRead (PIFACE_BASE + button) == LOW)
{
return liczba ; 
}else return 0;
delay (1) ;
}
int main (void)
{
int i, j,pin, czujnik ;
FILE *fp;
 char znak[30];
 int x=0,temp=0, temp2=0;
 int b2,b1,b0;
if(wiringPiSetup() == -1)
 exit(1);
for (pin = 0; pin <7; ++pin)
 pinMode(pin, OUTPUT);
pinMode(8, OUTPUT);
 
for (pin = 9; pin <17; ++pin){
 pinMode(pin, INPUT);
 pullUpDnControl (PIFACE_BASE + pin, PUD_UP) ;
 digitalWrite    (PIFACE_BASE + pin, 0) ;
}
for (;;)
{
 czujnik = 0;
 czujnik = scanButton(9,1) + scanButton(10,2) + scanButton(11,4) + scanButton(12,8) + scanButton(13,16) + scanButton(14,32) + scanButton(15,64) + scanButton(16,128);
 
 if(temp2!=czujnik){
 temp2=czujnik;
 fp=fopen("/ram/czujnik.txt","w");
 if (fp != NULL){ 
 fprintf(fp, "%d",czujnik);
 fclose(fp);
 }
 } 
 delay (100) ;
 fp=fopen("/ram/test.txt","r");
 if (fp != NULL){ 
 fgets(znak,30,fp);
 x=atoi(znak); 
 fclose(fp); 
 if(temp!=x)
 {
 temp=x;
 if(x>=128){
  x=x-128 ;
  digitalWrite    (PIFACE_BASE + 8, 1) ;
 }
 else
  digitalWrite    (PIFACE_BASE + 8, 0) ; 
 if(x>=64){
  x=x-64 ;
  digitalWrite    (PIFACE_BASE + 6, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 6, 0) ;
 if(x>=32){
  x=x-32 ;
  digitalWrite    (PIFACE_BASE + 5, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 5, 0) ;
 if(x>=16){
  x=x-16 ;
  digitalWrite    (PIFACE_BASE + 4, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 4, 0) ;
 if(x>=8){
  x=x-8 ;
  digitalWrite    (PIFACE_BASE + 3, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 3, 0) ;
 if(x>=4){
  x=x-4 ;
  digitalWrite    (PIFACE_BASE + 2, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 2, 0) ;
 if(x>=2){
  x=x-2 ;
  digitalWrite    (PIFACE_BASE + 1, 1) ; 
 }
 else
  digitalWrite    (PIFACE_BASE + 1, 0) ;
 if(x>=1){
  x=x-1 ;
  digitalWrite    (PIFACE_BASE + 0, 1) ;
 }
 else
  digitalWrite    (PIFACE_BASE + 0, 0) ;
}
 }else fclose(fp); 
}
return 0 ;
}

Mając już program, który będzie odbierał dane i przesyłał na piny trzeba napisać wygodną aplikację dla zwykłego użytkownika. Jeśli jesteście początkujący i chcielibyście zrobić to samodzielnie, to proponuje od prostego pola input w formie i wysłanie liczby za pomocą przycisku i PHP. Z czasem można dodać jakieś ładne grafiki i JavaScripta, a na końcu technologię AJAX, która będzie odświeżała nam stronę w tle.

Moja strona podzielona jest na 3 moduły.

 

  • Głowny, który wyświetla obrazki i dane.
  • Moduł wysyłający dane z formularza do odpowiednich plików za pomocą PHP
  • moduł, który pobiera dane z czujników, termometrów itp oraz odświeża to na stronie co 1 sekundę.

 

Moduł główny wygląda tak:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="/omnie/./jquery.js"></script>
<title> inteligentny dom</title>
 
<!--<link rel="stylesheet" type="text/css" href="/omnie/./style.css"/>-->
<style type="text/css">
 @import url('style.css');
</style>
<meta http-equiv="content-language" content="pl" />
 
<script type="text/javascript">
 
 $(document).ready(function(){
  $("#lewo").mouseup(function(){
  $.post("wyslij.php", {"pole6":-1});
  });
 });
 $(document).ready(function(){
  $("#prawo").mouseup(function(){
  $.post("wyslij.php", {"pole7":-1});
  });
 });
 $(document).ready(function(){
  $("#lewo").mousedown(function(){
  $.post("wyslij.php", {"pole6":1});
  });
 });
 $(document).ready(function(){
  $("#prawo").mousedown(function(){
  $.post("wyslij.php", {"pole7":1});
  });
 });
 
 $(document).ready(function(){
  $("#up").mouseup(function(){
  $.post("wyslij.php", {"pole4":-1});
  });
 });
 $(document).ready(function(){
  $("#down").mouseup(function(){
  $.post("wyslij.php", {"pole5":-1});
  });
 });
 $(document).ready(function(){
  $("#up").mousedown(function(){
  $.post("wyslij.php", {"pole4":1});
  });
 });
 $(document).ready(function(){
  $("#down").mousedown(function(){
  $.post("wyslij.php", {"pole5":1});
  });
 }); 
 function wywolaj(pin, pole){
 var str ="";
 str +=pin;
 var myselect = document.getElementById(str);
 m="g={"+pole+":"+myselect.options[myselect.selectedIndex].value +"}";
 eval(m);
 $.post("wyslij.php", g );
 }
 function odswiezanie(){
 
 $(document).ready(function(){
  $("#odswiez").load("./czujniki.php");
 });
 setTimeout("odswiezanie()",1000);
 } 
</script>
</head>
<body id="tlo">
 
<p id="info"> Witaj numerze <? echo getenv("REMOTE_ADDR"); ?> </BR> Trafiłeś na projekt dzięki któremu będziesz mógł sterować każdym urządzenie w swoim domu.</p>
<p id="info2"> Interesuje się elektroniką i programowaniem?</BR> Zapraszam na:</BR><a href="http:\\avrkwiat.nstrefa.pl">AVRKwiat.nstrefa.pl</a> </p>
 
<img id="ramka" src="/omnie/./ramka.png" width="300" height="460"/>
<img id="ramka2" src="/omnie/./ramka.png" width="300" height="460"/>
<img id="logo" src="/omnie/./logo.jpg" width="600" height="186"/>
<img id="monitor" src="/omnie/./monitor.png" width="638" height="602"/>
<img id="live" src="http://<?php echo $_SERVER['HTTP_HOST'];?>:8083/?action=stream" width="580" height="330"/>
 
<form method="post">
<select id="pin0" name="pole0" size="1" onChange="wywolaj('pin0','pole0')">
 <option value="0" selected="selected">(relay0)</option>
 <option value="-1">ON</option>
 <option value="1">OFF</option>
</select>
<select id="pin1" name="pole1" size="1" onChange="wywolaj('pin1','pole1')">
 <option value="0" selected="selected">(relay1)</option>
 <option value="-1">ON</option>
 <option value="1">OFF</option>
</select>
<select id="pin2" name="pole2" size="1" onChange="wywolaj('pin2','pole2')">
 <option value="0" selected="selected"> (relay2)</option>
 <option value="-1">ON</option>
 <option value="1">OFF</option>
</select>
<select id="pin3" name="pole3" size="1" onChange="wywolaj('pin3','pole3')">
 <option value="0" selected="selected"> (relay3)</option>
 <option value="-1">ON</option>
 <option value="1">OFF</option>
</select>
<p id="pin4"> up </p>
<p id="pin5"> down </p>
<p id="pin6"> left </p>
<p id="pin7"> right </p>
</form>
<button id="lewo"> left</button>
<button id="prawo"> right</button>
<button id="up"> up </button>
<button id="down"> down</button>
<div id="odswiez">  
</div>
<script language=javascript>
 odswiezanie();
</script>
</body></html>

Moduł wysyłający dane do serwera:

<?php
/*******************************
Pobieranie danych z formulaza za pomoca post
******************************/
 $pole0 = trim($_POST['pole0']);
 $pole1 = trim($_POST['pole1']);
 $pole2 = trim($_POST['pole2']);
 $pole3 = trim($_POST['pole3']);
 $pole4 = trim($_POST['pole4']);
 $pole5 = trim($_POST['pole5']);
 $pole6 = trim($_POST['pole6']);
 $pole7 = trim($_POST['pole7']);  
/*******************************
Wysywalnie pobranych danych do pliku
******************************/ 
 $fp = fopen("/ram/test.txt", "r"); 
 $dane = fread($fp,filesize("/ram/test.txt"));
   fclose($fp);
 if ($pole0 == 1)
 $dane = $dane | 1;
 else if ($pole0 == -1)
 $dane = $dane & ~1;
 if ($pole1 == 1)
 $dane = $dane | 2;
 else if ($pole1 == -1)
 $dane = $dane & ~2;
 if ($pole2 == 1)
 $dane = $dane | 4;
 else if ($pole2 == -1)
 $dane = $dane & ~4;
 if ($pole3 == 1)
 $dane = $dane | 8;
 else if ($pole3 == -1)
 $dane = $dane & ~8;
 if ($pole4 == 1)
 $dane = $dane | 16;
 else if ($pole4 == -1)
 $dane = $dane & ~16;
 if ($pole5 == 1)
 $dane = $dane | 32;
 else if ($pole5 == -1)
 $dane = $dane & ~32;
 if ($pole6 == 1)
 $dane = $dane | 64;
 else if ($pole6 == -1)
 $dane = $dane & ~64;
 if ($pole7 == 1)
 $dane = $dane | 128;
 else if ($pole7 == -1)
 $dane = $dane & ~128;
 $fp = fopen("/ram/test.txt", "w");
 fputs($fp, $dane);
 fclose($fp);   
 ?>

Moduł odświeżający za pomocą AJAX:

<?php
 
/*****************************
ilość osób online i statystyki
*****************************/
 
 function counter($t1=300,$t2=3600,$f="/ram/counter.txt"){
  global $HTTP_COOKIE_VARS;
  $a=getenv("REMOTE_ADDR");
  $t=time();
 $p=fopen($f,"a+");
 if ($p!= NULL){
 
  flock($p,2);
  $h=array_pad(explode("|",chop(fgets($p,100))),4,0);
  while(!feof($p)){
  $e=explode("|",$m=chop(fgets($p,100)));
  if($e[1]>$t&&$e[0]!=$a)$b[]=$m;
  }
  $b[]=$a."|".($t+$t1);
  $h[0]=count($b);
  if(!$HTTP_COOKIE_VARS["lastvisit"]){
  $h[1]++;
  $h[2]++;
  if($h[3]!=($d=date("d"))){
  $h[2]=1;
  $h[3]=$d;
  }
 }
  }
  setcookie("lastvisit",1,$t+$t2);
  ftruncate($p,0);
  fputs($p,join("|",$h)."\n".join("\n",$b));
  flock($p,3);
  fclose($p);
 return array($h[1],$h[2],$h[0]);
  }
 
 $tab = counter();
 echo '<p id="online">Aktualnie online: ';
 echo $tab[2];
 echo'</p>';
 
 
/*****************************
odczyt z termometru
*****************************/
 
 $sciezkaadres = '/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves';
 $adres = implode(file($sciezkaadres));
 //ucina wszystko po 15 lini
 $adres = substr($adres,0,15);
 $file = "/sys/bus/w1/devices/".$adres."/w1_slave";
 
 //czytanie linia po lini z konkretnego czujnika
 $lines = file($file);
 
 //wez z drugiej lini temperature
 $temp = explode('=',$lines[1]);
 
 //robienie ladnego formatu do odczytu
 $temp=number_format($temp[1]/1000,1,'.','');
   
 
 echo '<p id="temp1"> Temperatura pierwsza: </BR> ';
 echo $temp;
 echo'&#186C</p>';
 
/*****************************
wyświetlenie czasu serwera
*****************************/
 
 echo '<p id="czas">';
 echo date('H:i:s');
 echo'</p>';
 
/*****************************
odczyt z pinów wyjściowych OUTPUT
*****************************/
 
 $fp = fopen("/ram/test.txt", "r");
 if ($fp!= NULL)
 {
 $pobrane = fread($fp,filesize("/ram/test.txt"));
 fclose($fp);
 }
 
 $test=$pobrane & 1;
 if ($test>=1)
 echo '<p id="wartosc0">OFF</p>';
 else echo '<p id="wartoscon0">ON</p>';
 
 $test=$pobrane & 2;
 if ($test>=1)
 echo '<p id="wartosc1">OFF </p>';
 else echo '<p id="wartoscon1">ON </p>';
 
 $test=$pobrane & 4;
 if ($test>=1)
 echo '<p id="wartosc2">OFF </p>';
 else echo '<p id="wartoscon2">ON </p>';
 
 
 $test=$pobrane & 8;
 if ($test>=1)
 echo '<p id="wartosc3">OFF </p>';
 else echo '<p id="wartoscon3">ON </p>';
 
 $test=$pobrane & 16;
 if ($test>=1)
 echo '<p id="wartoscon4">ON</p>';
 else echo '<p id="wartosc4">OFF</p>';
 
 $test=$pobrane & 32;
 if ($test>=1)
 echo '<p id="wartoscon5"> ON </p>';
 else echo '<p id="wartosc5">OFF</p>';
 
 
 $test=$pobrane & 64;
 if ($test>=1)
 echo '<p id="wartoscon6">ON </p>';
 else echo '<p id="wartosc6">OFF</p>';
 
 
 $test=$pobrane & 128;
 if ($test>=1)
 echo '<p id="wartoscon7">ON </p>';
 else echo '<p id="wartosc7">OFF</p>';
 
 
/*****************************
odczyt pinów wejściowych (czujniki) INPUT
*****************************/
 
 $fp = fopen("/ram/czujnik.txt", "r");
 if ($fp!= NULL){
 $pobrane1 = fread($fp,filesize("/ram/czujnik.txt"));
 fclose($fp);
 }
 
 $test=$pobrane1 & 1;
 if ($test>=1)
 echo '<p id="czujnikon0">ON (pin 9)</p>';
 else echo '<p id="czujnik0">OFF (pin 9)</p>';
 
 
 $test=$pobrane1 & 2;
 if ($test>=1)
 echo '<p id="czujnikon1">ON (pin 10)</p>';
 else echo '<p id="czujnik1">OFF (pin 10)</p>';
 
 $test=$pobrane1 & 4;
 if ($test>=1)
 echo '<p id="czujnikon2">ON (pin 11)</p>';
 else echo '<p id="czujnik2">OFF (pin 11)</p>';
 
 $test=$pobrane1 & 8;
 if ($test>=1)
 echo '<p id="czujnikon3">ON (pin 12)</p>';
 else echo '<p id="czujnik3">OFF (pin 12)</p>';
 
 $test=$pobrane1 & 16;
 if ($test>=1)
 echo '<p id="czujnikon4">ON (pin 13)</p>';
 else echo '<p id="czujnik4">OFF (pin 13)</p>';
 
 $test=$pobrane1 & 32;
 if ($test>=1)
 echo '<p id="czujnikon5">ON (pin 14)</p>';
 else echo '<p id="czujnik5">OFF (pin 14)</p>';
 
 $test=$pobrane1 & 64;
 if ($test>=1)
 echo '<p id="czujnikon6">ON (pin 15)</p>';
 else echo '<p id="czujnik6">OFF (pin 15)</p>';
 
 $test=$pobrane1 & 128;
 if ($test>=1)
 echo '<p id="czujnikon7">ON (pin 16)</p>';
 else echo '<p id="czujnik7">OFF (pin 16)</p>';
 
?>

Na koniec wystarczy dodać tylko CSS, aby wszystko ładnie wyglądało i  dorzucić biblioteki JQuery, żeby wszystko działało, a następnie cieszyć się wykonaną pracą :)

iqhome.avrkwiat.nstrefa.pl