AdSense

Sonntag, 29. September 2013

Raspberry PI - C++ - Socket öffnen

(English version) Heute will ich einen kleinen Post zum Thema Socket öffnen in C++ schreiben. Der Grund dafür ist, dass mein Raspberry PI vieles ansteuert, ausliest, etc. Das dann alles über Dateien zu regeln ist keine so schöne Lösung, daher will ich direkt über das Netzwerk mit dem Raspberry PI reden können. Dafür muss am Raspberry PI ein Netzwerk-Socket aufgemacht werden. Vieles von dem Code habe ich einfach aus anderen Quellen übernommen, da ich ja nur das Empfangen und Senden der Nachricht benötige. Außerdem habe ich die Nachrichtenlänge auf 256 Bytes festgesetzt. Das Ganze geht folgendermaßen:

//define variables 
int sockfd, newsockfd, portno = 82; //number of port
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n; 
 
//create socket 
sockfd = socket(AF_INET, SOCK_STREAM, 0);

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);

bind(sockfd, (struct sockaddr *) &serv_addr,
        sizeof(serv_addr));
listen(sockfd,5);
clilen = sizeof(cli_addr); 
 
//accept tcp clients 
while(true)
{
  //accept client 
  newsockfd = accept(sockfd, 
            (struct sockaddr *) &cli_addr, 
            &clilen); 
  bzero(buffer,256);
  //read client message into buffer
  n = read(newsockfd,buffer,256);
  //write message to client
  n = write(newsockfd,"I got your message, this should be 256 bytes long",256);

  close(newsockfd);
}
close(sockfd);

Freitag, 27. September 2013

Raspberry PI - C++ - Threads

(English version) Threads in C# zu implementieren ist total einfach. Will man jedoch auf dem Raspberry PI soetwas mit C++ haben, so muss man ein paar Kleinigkeiten beachten. Ein Thread wird folgendermaßen erzeugt und gestartet, #include <thread> muss ganz oben stehen.

std::thread networkThread (networkCommunication);
networkThread.detach();


Zum Compilieren müssen jetzt aber noch zwei Optionen angegeben werden, sonst funktioniert das nicht:

-std=c++0x
-pthread


Das ganze Programm wird dann wie folgt compiliert:

g++ ./myProgram.c++ -o outputName -std=c++0x -pthread

Damit kann mann dann auch am Raspberry PI Threads erzeugen und lustige Sachen damit machen.

Dienstag, 24. September 2013

Einfluss der Corioliskraft auf ein Scharfschützen-Projektil

(English version) Vor einiger Zeit sah ich den Film Shooter (Wikipedia). Recht am Anfang wird über einen Schuss aus 1,5 km Entfernung gesprochen. Dabei wird auch erwähnt, dass bei diesem Schuss sogar die Corioliskraft eine Rolle spielt. Das will ich heute hier durchrechnen.

Zuerst eine kurze Einführung zum Thema Corioliskraft. Die Corioliskraft zählt zu den sogenannten Scheinkräften, welche in rotierenden Bezugssystemen auftritt. Die Kraft lässt sich recht einfach herleiten, indem man die Bewegungsgleichungen eines freien Teilchens in ein rotierendes Koordinatensystem transformiert (siehe dazu auch z.B. H.-R. Trebin, Theoretische Physik 1, Mechanik). Für meine Rechnung ist dies jedoch nicht vonnöten. Anschaulich erklärt tritt die Kraft auf, weil sich die Erde unter dem Geschoss weiterdreht.

Kommen wir zur Rechnung. Um eine maximale Wirkung der Corioliskraft zu haben gehe ich davon aus, dass der Schuss entlang eines Längengrades ausgeführt wird. Geht man von einem Breitengrad von etwa 45° aus, so ist das Ziel etwa 1 km weiter von der Rotationsachse der Erde entfernt, daher bewegt sich das Ziel senkrecht zur Flugbahn etwas schneller als das Projektil. Nun will ich diese beiden Geschwindigkeiten berechnen. Der Erd-Durchmesser ist etwa 12 730 km. Im 45. Breitengrad entspricht das einem Radius von ziemlich genau 4500 km, also einem Umfang von 28274 km. Das führt bei einer Umlaufzeit von 86400 Sekunden zu einer Geschwindigkeit von 327,245 m/s. Vergrößert sich der Radius nun um 1 km, so ist der neue Umfang 28281 km und die neue Geschwindigkeit 327,326 m/s. Das macht eine Differenz von 0,081 m/s.

Im Film wird von etwa 6-10 Sekunden Flugzeit gesprochen, das würde 0,5 bis 0,8 Metern Abweichung vom Ziel entsprechen. Ich persönlich schätze die Flugzeit jedoch etwas anders, ein Geschoss mit 1000 m/s braucht für die Strecke nur 1,5 Sekunden, das macht dann immerhin 12 cm aus (was bereits über Treffer oder nicht Treffer entscheiden kann).

Real Time Clock DS1307

(English Version) Manchmal benötigt man bei Arduino-Projekten die aktuelle Uhrzeit oder das aktuelle Datum - z.B. wenn man einen Datenlogger bauen möchte. Eine Möglichkeit wäre natürlich, Arduino-intern eine softwarebasierte Uhr zu programmieren. Das hat jedoch den Nachteil, dass es Rechenzeit verbraucht. Der viel größere Nachteil ist jedoch, dass die Uhrzeit verloren ist, wenn der Arduino von der Versorgungsspannung getrennt wird. Die Uhrzeit müsste also bei jeder Inbetriebnahme neu eingestellt werden. Eine Lösung bieten hier Real-Time-Clock-Module wie das "Tiny RTC". Es arbeitet mit einem DS1307-IC und hat eine Stützbatterie, läuft also auch dann weiter, wenn der Arduino nicht mehr unter Strom steht.

Der DS1307 wird über I2C angesprochen - der Anschluss des Moduls an den Arduino ist also denkbar einfach: einfach SDA und SCL mit den entsprechenden Pins am Arduino verbinden sowie die Betriebsspannung anlegen. Wichtig ist dabei, dass die Anschlüsse auf der rechten Seite (also der Seite mit den 7 Pins) verwendet werden. Die Pins auf der anderen Seite dienen zum Anschluss des EEPROM-Chips, der ebenfalls auf dem Modul verbaut ist.
Auf der rechten Seite gibt es noch einen Pin zum Zugriff auf die Batterie-Spannung (BAT) sowie den Pin SQ. Der IC kann ein Rechtecksignal erzeugen, das hier abgegriffen werden kann. Darauf werde ich aber nicht näher eingehen. Auf dem Modul kann außerdem ein Temperatursensor vom Typ DS18B20 aufgelötet werden. Auf den Sensor könnte mit dem letzten verbleibenden Pin DS zugegriffen werden. Aber auch hierauf werde ich in diesem Beitrag nicht weiter eingehen.

Der IC kann Datum und Uhrzeit (Jahr, Monat, Tag, Wochentag, Stunde, Minute, Sekunde) ausgeben. Die Werte werden in einem SRAM-Register gespeichert und können von dort über I2C ausgelesen werden. Das Register ist wie folgt aufgebaut:
In den Bits 0 bis 6 des Registers 0 sind die Sekunden gespeichert, das Bit 7 CH gibt an, ob die Uhr aktiv ist oder nicht. Wird das Bit auf 1 gesetzt, wird der Takt angehalten und die Uhrzeit wird nicht mehr weiter gezählt. Ist das Bit gelöscht, läuft der Takt und somit auch die Uhr weiter.
Die Bits 0 bis 6 des Registers 1 enthalten die Minuten.
Die Stunden werden im Register 2 gespeichert. Ist das Bit 6 des Registers gesetzt, werden die Stunden im 12h-Format angegeben, das Bit 5 gibt dabei AM(low)/PM(high) an. Ist Bit 6 gelöscht, können die Stunden (wie für Europäer gewohnt) im 24h-Format ausgelesen werden.
Register 3 enthält den aktuellen Wochentag - dabei entspricht 1 Sonntag, 2 Montag usw.
In den Registern 4 bis 6 werden Tag, Monat und Jahr gespeichert.
Register 7 dient zur Konfiguration des Rechtecksignal-Generators. Die restlichen Register können als batteriegestützer RAM verwendet und frei beschrieben werden.

Die Zahlen werden im BCD-Format (Binary Coded Decimal) ausgegeben. Dabei geben die Bits 0 bis 3 eines Bytes die Einer und die restlichen Bits die Zehner einer Zahl aus. Die Zahl 18 wäre somit also 0001'1000, die Zahl 34 entspräche 0011'0100 und so weiter.

Der DS1307 kann über die Adresse 0x68 im I2C-Bus angesprochen werden.

Bei der ersten Inbetriebnahme des Moduls muss die Uhrzeit eingestellt werden.
#include "Wire.h"

#define DS1307_ADDRESS 0x68

void setup(){
  Wire.begin();
    
  Serial.begin(9600);
  
  byte second =      0; //0-59
  byte minute =      44; //0-59
  byte hour =        22; //0-23
  byte weekDay =     1; //1-7
  byte monthDay =    22; //1-31
  byte month =       9; //1-12
  byte year  =       13; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
    
  Wire.write(0x00); //Pointer auf Register 0
  
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.endTransmission();
  
}

void loop(){
}

byte decToBcd(byte val){
//Dezimal in BCD konvertieren
  return ( (val/10*16) + (val%10) );
}

In den Variablen kann die aktuelle Uhrzeit bzw. das Datum eingestellt werden. Mit dem Befehl beginTransmission() wird dann die Übertragung zum Modul gestartet. Dzu wird der Pointer auf das Register 0 (das mit den Sekunden) gesetzt. Nun können Uhrzeit und Datum übertragen werden. Dazu werden die in den Variablen gespeicherten Werte zuerst vom Dezimal- ins BCD-Format konvertiert und dann mit write() ins Register des ICs geschrieben. Nach dem write()-Befehl springt der Arduino automatisch zum nächsten Register.

Ist der IC einmal richtig eingestellt, zählt er munter bis ans Ende aller Tage (bzw. bis ans Ende der Batterie) die Zeit hoch und kann jederzeit mit folgenden Befehlen ausgelesen werden:

#include "Wire.h"
#define DS1307_ADDRESS 0x68

void setup(){
  Wire.begin();
  Serial.begin(9600);
}

void loop(){
  
  //Pointer auf Register 0 setzen
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();

  //Zeit abfragen
  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read());
  int weekDay = bcdToDec(Wire.read());
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //Datum ausgeben im Format dd.mm.yy - hh:mm:ss
  Serial.print(monthDay);
  Serial.print(".");
  Serial.print(month);
  Serial.print(".");
  Serial.print(year);
  Serial.print(" - ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
  delay(1000);
}

byte bcdToDec(byte val)  {
//BCD in Dezimal konvertieren
  return ( (val/16*10) + (val%16) );
}

In der loop() wird zuerst der Pointer auf das Register 0 gesetzt (wir wollen als erstes die Sekunden auslesen), dann werden mit dem Befehl requestFrom() aus diesem und den folgenden Registern 7 Bytes angefordert. Diese werden dann mit dem read()-Befehl empfangen, vom BCD- ins Dezimal-Format konvertiert und zum Schluss über die serielle Schnittstelle ausgegeben.

Mittwoch, 18. September 2013

ATMega - Alles um den Faktor 8 langsamer?

(English version) Genau dieses Problem trat bei mir auf: Ich habe einen ATMega 1284-P welcher mit einem 16 MHz Quarz läuft. Allerdings lief alles um den Faktor 8 zu langsam. Die Fuses (Ich benutze AVR Studio 4, da sieht man nicht alles) waren alle korrekt eingestellt. Nach einiger Zeit auf Google kam ich endlich auf die Lösung: Das Fuse-Bit CKDIV8 ist 0, also wird die Clock durch 8 geteilt. Leider kann man auf dieses Fuse-Bit im AVR Studio 4 nicht direkt zugreifen, es gibt jedoch eine recht einfache Möglichkeit, den Clock Divider auszuschalten:

#include <avr/power.h> 

Und dann direkt am Anfang vom Programm:

clock_prescale_set(clock_div_1);

Damit war bei mir das Problem dann behoben.

Dienstag, 17. September 2013

Musikplayer - Handy-Fernsteuerung

(English version) Wie in diesem Post beschrieben habe ich einen eigenen Musikplayer mit C# und WPF geschrieben. Da es bei größeren Wiedergabelisten durchaus vorkommen kann, dass einem mal ein Lied nicht gefällt, gibt es Hotkeys für den PC. Was ist aber, wenn man gerade gemütlich auf dem Bett liegt und man keine Lust hat, aufzustehen? Dafür habe ich eine App geschrieben, mit welcher man die grundlegenden Hotkeys (Play/Pause, nächstes Lied, vorheriges Lied) ausführen kann. Diese App kann man hier herunterladen.

Zur Verwendung der App: Die App kann man einerseits starten und dann auf die entsprechenden Buttons klicken, es gibt jedoch auch ein Widget, welches den Klick zum App Öffnen spart. Die App bietet jedoch mehr Funktionen, sogar das suchen nach einem Lied ist möglich.

In der App muss man nun IP, Port (Der Player macht standardmäßig einen Socket auf Port 7200 auf) und Passwort (welches man im Player mit F2 festlegen kann) eingeben. Dabei kann die IP lokal sein (z.B. wenn das Handy im selben Netzwerk ist wie das Handy) oder auch eine Internet-IP. Dafür muss man jedoch am Router noch eine entsprechende Port-Weiterleitung einrichten. Das Handy kann den Player in diesem Fall unabhängig davon steuern, ob es im WLAN oder im mobilen Netzwerk ist.