Informatik und Kram

Da wir lange nicht wußten, wo wir das für die Uni ausgearbeitete Material unterbringen sollten und auch einen schrecklichen Drang hatten der Welt diverse Sachen aufzudrücken...

Webcam, Servos, Parallel-Port, Ajax
de-flagge aktiviert en-flagge aktiviert

Ja, ihr habt richtig gehört. Ich bin heut und gestern mal wieder total ausgerastet und hab mal ganz interdisziplinär abgenerdet. Eigentlich sollt ich für Mathe lernen, aber ich muss was cooles bauen, solang der Andieh weg ist, dass der neidisch wird :-)
Wo fang ich an...

Die Cam

Im letzten Artikel hab ich ja schon über die Pollin-Funk-Cam und deren Betrieb unter Linux geschrieben.
Da mir motion allein nicht mehr ausreicht und ich mal wieder nerdig drauf war, wollte ich mir meine eigene pan/tilt kamera bauen. Alles was geblieben ist, ist das motion mir die Bilder von der cam liefert und Snapshots macht.

Die Servos

Zunächst mal hab ich mir zwei handelsübliche Servos geschnappt, und die zusammengebaut, einer für die X-Achse, einer für die Y-Achse. gesteuert werden die Teile von meinem innig geliebten Atmega8, der widerum seine Befehle über den Parallelport meines PCs bekommt (schenk mir mal jemand den FTDI-Chip, dann bau ich das Ding für USB!).

Der Atmega

Hier gibts nich allzuviel zu sagen, ich benutze für jeden Servo einen PWM-Port, natürlich getrennt steuerbar. Der Atmega bekommt die Steuerkommandos wie gesagt über die Kabel vom Parallelport und reagiert dann drauf.
Den Atmega sowie eine Buchse für die Kabel vom Parallelport und eine Buchse für die Stromversorgung der Servos sind auf ner kleinen Platine. Code findet ihr hier:
#include <avr/io.h>
#include <util/delay.h>

void my_delay(int ms){
	int y=0;
	for(y=0;y<ms;y++){
		_delay_ms(10);
	}
}


main(){
	int x=0;
	DDRD=0x00;   //D-Pins als Eingänge
	PORTD=0x00;  //PullUps aus
	
        DDRB=0xFF;    //B-Pins als Ausgänge

	OCR1A = 100;  // steuert Motor 1
	OCR1B = 100;  // steuert Motor 2

	ICR1=10000;
	TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|
                      (1<<COM1B1)|(0<<FOC1A)|(0<<FOC1B)|
                      (1<<WGM11)|(0<<WGM10);
	TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)|
                      (0<<CS12)|(1<<CS11)|(0<<CS10);

	my_delay(100);

	for(;;){
		// -------------------- X-ACHSE ------------------------
                // Die Leitungen vom Parallel-Port kommen bei
                // PD0 und PD1 rein
                // ----------------------------------------------------------
		if(!bit_is_set(PIND,0) && (bit_is_set(PIND,1))){
				OCR1A += 10;
				my_delay(50);
		}

		if(!bit_is_set(PIND,1) && (bit_is_set(PIND,0))){
				OCR1A -= 10;
				my_delay(50);
		}
		// -----------------------------------------------------

		// -------------------- Y-ACHSE ------------------------
                // Leitungen vom ParPort an PD2 und PD3
                // ----------------------------------------------------------
		if(!bit_is_set(PIND,2) && (bit_is_set(PIND,3))){
				OCR1B += 10;
				my_delay(50);
		}

		if(!bit_is_set(PIND,3) && (bit_is_set(PIND,2))){
				OCR1B -= 10;
				my_delay(50);
		}
		// -----------------------------------------------------
	}

	return 0;
}
Als Tip: PWM-Signale kommen also bei PB1 und PB2 raus!

Parallel-Port

Für Linux gibts hier ne super Bibliothek, nämlich parapin (http://parapin.sourceforge.net/).
Entpacken, dann gibts da ein Verzeichnis, das nennt sich examples/.
Dort kann man ganz gut sehen, wie die lib funktioniert, ich hab ein Programm geschrieben,
mit dem ich direkt über die Tastatur die Servos kontrollieren kann, und eins für meinen Webserver, so zur Heimüberwachung, und das seht ihr hier:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include "parapin.h"

using namespace std;

int main(int argc, char *argv[])
{
  int i;
  int prev = 0;

  if (pin_init_user(LPT1) < 0)
    exit(0);

  pin_output_mode(LP_DATA_PINS | LP_SWITCHABLE_PINS);

  i = -1;

  // Pin 2 Versorgt den Atmega mit Strom,
  // Pin 3 -> rechts
  // Pin 4 -> links
  // Pin 5 -> runter
  // Pin 6 -> hoch 

  //printf("Strom für Atmega (Pin 2)\n");
  set_pin(LP_PIN[2] | prev);
      if(argv[1]){
        // Kommando-Zeilen-Argument
        // speichern
	string test = argv[1];
	if(test[0] == 'h'){ //hoch
	   set_pin(LP_PIN[6] | prev);
           // kurz warten, damit der Servo
           // lang genug bewegt wird
	   usleep(100000);
           clear_pin(LP_PIN[6] | prev);
	}
	if(test[0] == 'r'){
           if(test[1] == 'u'){ // runter
	      set_pin(LP_PIN[5] | prev);
	      usleep(100000);
              clear_pin(LP_PIN[5] | prev);
	   }
	   if(test[1] == 'e'){ // rechts
	      set_pin(LP_PIN[3] | prev);
	      usleep(100000);
              clear_pin(LP_PIN[3] | prev);
	   }
	}
	if(test[0] == 'l'){ // links
	   set_pin(LP_PIN[4] | prev);
	   usleep(100000); 
           clear_pin(LP_PIN[4] | prev);
	}
      }
}
Jaja, ich weiß, böser Code, man kann switch benutzen, und bestimmt noch paar andere Sachen falsch, nicht schlagen!!

Web-Steuerung mit AJAX

Das ganze will ich natürlich bequem übers Internet steuern können, und natürlich auch sehen was so geht. Am Anfang stand natürlich erstmal reines PHP, mit nem einfachen http-reload.
Nervig, weil die Seite ja jedes mal neu geladen wird.
Also muss irgendwas her, dass mir zulässt, die Webcam über Buttons zu steuern, meine externen Funktionen aufzurufen, und die Bilder zu aktualisieren, ohne die Seite neu zu laden.
Auch hier wieder erstmal munter alles zusammengehackt, hat auch im Prinzip ganz gut funktioniert, aber ich habe die Javascript-Funktionen zum Bildertausch mit setTimeout periodisch aufgerufen, was nie so wirklich wollte (zu lang gewartet, oder die Funktion gar nicht mehr gestartet).
Dank dem Meissner bin ich dann bei mootools gelandet, ein nettes toolkit für so Ajax-Geschichten.
Habe einige Zeit gebraucht, um mich einzulesen, aber jetzt funktioniert das super!
Zur Technik: Das Programm, das den Parallel-port steuert, hab ich web-servo genannt.
Immer wenn es mit einem Parameter aufgerufen wird, gibt es für kurze Zeit die Signale über den Parallelport an den Atmega, um die Servos steuern.
Dieses Programm wird aus einem PHP-Skript folgendermassen aufgerufen:
system('/usr/bin/web-servo hoch');
Motion legt mir mit der snapshot-Funktion automatisch eine Datei lastsnap.jpg ab, die ich bequem mit dem AJAX periodisch aktualisieren kann:
<html>
<body>
<script language="JavaScript" type="text/javascript" src="mootools-1.2-core.js"></script>
<script language="JavaScript">
function go(){
        var random = $random(0, 100000);

        $('out').load('capture.php');
        $('neustes').set('src','lastsnap.jpg?' + random);

}
</script>
<button onclick="servo-left();">left</button>
<button onclick="servo-right();">right</button>
<button onclick="servo-up();">up</button>
<button onclick="servo-down();">down</button>

<div id="out"></div>
<img id="neustes" src="lastsnap.jpg">
<script language="JavaScript">
   go.periodical(2000);
</script>
</body>
</html>
Ja, so easy ist das mit Mootool.
Und zu guter Letzt, wie schon gewohnt, das Video:

Kommentare

Niiiice, besonders die Evolution vom Code zum Vergleich mit dem letzten Post ist regelrecht Phänomenal. Vielleicht sollten wir uns noch über Kommentare streiten, mag die lieber, wenn die _nicht_ mehr Platz einnehmen als der Code, aber informativer ist es wohl genau so. Eine Kleinigkeit zum haarespalten: bitte immer "int" vor main(), sonst passiert eigentlich nix (ausser wenn mans halt auch mal mit nem anderen Compiler compilieren würde) aber das ist so "standard" wenn man das so nennen kann. Ajax mit MooTools == geil! Lieb das Ding, dort mag ich aber das "random" gar nicht, klar super workaround, habsch auch schon 20mal irgendwo verwendet, aber ich traue MooTools eigentlich zu, dass es ohne gehen müsste... Achso, nen Schaltplan von der Servosteuerung fänd ich klasse, aber du hast wahrscheinlich genauso wenig nen anständiges App gefunden um "mal schnell" nen Schaltplan zu erstellen, eagle is halt nich grade äääh bequem...

jau, schaltplan ist oben!
ich mag eagle eigentlich..sobald man sich mal behalten kann, in welcher lib welches Teil steckt gehts eigentlich relativ schnell find ich..und der nischo hat ja sogar ein tool ausgegraben, was die boards von eagle in 3d rendern kann...

hi - nettes dings, dass du da bastelst! Zudem funktionierts ja bisher ganz hübsch. Wie greifst du den stream von der cam ab? oder reloadest du nur über image.cgi? hab selbst gern so ne cam, die will mir aber keinen stream ausspucken, sodass ich den woanders reinbekomme und weiterverarbeiten kann (objekterkennung etc) ... falls Dir/Euch was cooles dazu einfällt: gerfry@gmx.de - superklasse jedenfalls!

Hi Fry!
Bei meinem setup lade ich immer nur Einzelbilder, die ich mithilfe von "motion" jede sekunde aufnehme und einfach nur per ajax neu in die seite lade..
Wenn du den stream direkt abgreifen und bearbeiten/ Objekte erkennen willst, und linux benutzt,
solltest du dir mal den folgenden Artikel ankucken, ist zwar linux-lastig, aber sollte unter windows auch funktionieren:http://www.infolexikon.de/blog/opencv/Hoffe ich konnte dir helfen!

Hallo- ich muss mich auf diesem Wege für Dein tolles Projekt bedanken - es hat mir ermöglicht mein eigenes (Windows- bzw. Python-basiertes) Projekt in Rekordzeit umzusetzen. Details können hier nachgelesen werden: http://grauonline.de/wordpress/?p=37Viele Grüße, Alexander

Kommentar schreiben