IT-Service Johannes Hermsdorf Satow

  • Besucher StatistikBesucher Statistik
  • » 1 Online
  • » 4 Heute
  • » 58 Woche
  • » 118 Monat
  • » 2.325 Jahr
  • » 12.029 Gesamt
  • Rekord: 34 (02.08.2019)
Akzeptieren

Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies.
Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu.

Ein einfacher Yacht-Navigator


Systemvoraussetzungen:


    Hardware:
    ∘ Note- oder Netbook
    ∘ USB-GPS-Empfänger (empfohlen:USB-GPS-Empfänger VT-200)
    
    Software:
    ∘ Betriebssystem: LINUX (empfohlen UBUNTU, notfalls WINDOWS)
    ∘ Perl
    ∘ Das hier beschriebene Programm 'navi.pl'
    ∘ System- und Programmiererfahrung in Perl und Linux !
    
In Ubuntu müssen noch folgende Zusatzprogramme installiert werden:
    ∘ socat
    ∘ cpulimit
    ∘ wine1.7 oder höher
    
Mit dem Befehl 'sudo apt-get install <Programmname>' ist dies leicht zu bewerkstelligen.
Diese Zusatzprogramme sind optional und werden nur benötigt, wenn gleichzeitig ein Kartenplotter (SeaClear o.ä.) auf dem Notebook betrieben werden soll.

Perl ist in den LINUX-Distributionen bereits enthalten, jedoch müssen folgende Module nachinstalliert werden:
    ∘ Tk
    ∘ Tk::Dialog
    ∘ Device::SerialPort
    ∘ DateTime
    ∘ Thread
    ∘ Time::HiRes
    
Dies ist relativ einfach und geschieht mit dem Befehl 'cpanm <Modulname>' als Root.
Sollte cpanm noch nicht installiert sein: 'sudo apt-get install cpanm'
Das Perl-Modul Tk wird mit dem Befehl 'sudo apt-get install perl-tk' installiert.
    
Folgende Navigationsinformationen werden angezeigt:
Bild "/kategorien/Projekte/dateien/navigauge.png"
∘ Uhrzeit (MEZ) mit automatischer
    Umstellung Winter- und Sommerzeit
∘ Datum
∘ Anzahl der empfangenen GPS-Satelliten
∘ Qualität der Positionsbestimmung
∘ Echtzeit-Kompass
∘ Kurs über Grund (COG)
∘ Position
∘ Geschwindigkeit über Grund (SOG)
    
Es besteht die Möglichkeit der Helligkeitssteuerung des Bilschirmes (wichtig bei Nachtfahrten) und des Startens eines zusätzlichen Kartenplotter-Programms z.B. SeaClear oder OpenCPN.
Hierzu wird kein zusätzlicher GPS-Empfänger und auch keine zusätzliche Schnittstelle benötigt. Wie dies geschieht ist in Tips & Tricks beschrieben.




Das Listing zeigt das Programm 'navi.pl':

#!/usr/bin/perl -w
use warnings;
use strict;
use Tk;
use Tk::Dialog;
use utf8;
use Device::SerialPort;
use DateTime ;
use Thread;
use Time::HiRes qw(usleep nanosleep);
my $cpulimit = 25;
my $thread1;
my $thrun : shared = 0;
my $usbvsend ="/dev/ttyUSB98";
my $usbvread ="/dev/ttyUSB99";#Link zu .wine COM3 in wine
my $lsusb="";
my $pos = "Position";
my $center_x=250;
my $radius=300;
my $center_y=360;
my $i=0;
my $n = 0;
my $kursalt=10;
my $kurs=0;
my $move=1;
my $seaclear='/media/NAS/Dokumente/Hannes/Boot/SeaClear/SeaClear_2.exe';
my ($drawpos,$drawlog,$drawcompass,$drawmenu,$ob,$obv,$socatpid,$log,$time,$date,$sats,$brightness,
    @br,$scale,$startsc,$quit);
my ($mw,$readgps,$count,$dialog);
$ob = Device::SerialPort->new("/dev/ttyUSB0");

&initwindow;
&readserial;
MainLoop;

sub initwindow{
        $mw = new MainWindow();
        $mw->configure (-width=>"525",-height=>"500", -background=>'black');
        $mw->packPropagate(0);
                        
        $drawcompass = $mw->Canvas(-width => 500, -height => 210, -background=>"black",-relief => 'ridge',borderwidth=>8) -> pack;
        #Kompassmarke
        $drawcompass->createPolygon($center_x, $center_y-$radius-5,$center_x-10, $center_y-$radius-30,
                $center_x+10, $center_y-$radius-30,-outline =>'white',-fill=>'red',);
        #Kompassbogen
        $drawcompass->createArc($center_x - $radius, $center_y - $radius,$center_x + $radius, $center_y + $radius,
                -extent => -94,-start => 137,-outline => 'white',-width   => 4,-style => 'arc',);
        #Datum und Zeit
        $drawcompass->createText( $center_x-220,$center_y-330,-fill =>  'white',-text => 'Time',-font => 'Arial 12',-anchor => 'w',-tags=>'time');
        $drawcompass->createText( $center_x-220,$center_y-310,-fill =>  'white',-text => 'Date',-font => 'Arial 12',-anchor => 'w',-tags=>'date');
        #Satelliten
        $drawcompass->createText( $center_x+150,$center_y-330,-fill =>  'white',-text => 'Satelliten:',-font => 'Arial 12',-anchor => 'w',-tags=>'sats');
        $drawcompass->createText( $center_x+150,$center_y-310,-fill =>  'white',-text => 'Qualität:',-font => 'Arial 12',-anchor => 'w',-tags=>'quality');
        
        $drawpos = $mw->Canvas(-width => 500, -height => 120, -background=>"black",-relief => 'ridge',-borderwidth=>8) -> pack;
        $drawlog = $mw->Canvas(-width => 500, -height => 80, -background=>"black",-relief => 'ridge',-borderwidth=>8) -> pack;
        $drawpos->createText( $center_x, $center_y - $radius*0.9,-fill =>  'white',-text => $pos,-font => 'Arial 24',-tags => 'posi',);
        $drawpos->createText( $center_x, $center_y - $radius*1.05,-fill =>  'white',-text => "Kurs: " . $kurs ." °",-font => 'Arial 24',-tags => 'kurs',);
        &showlog;
        
        $drawmenu = $mw->Canvas(-width => 500, -background=>"black",-relief => 'solid',-borderwidth=>1) -> pack;
        
        #Helligkeitsregler
        $scale=$drawmenu->Scale(-from => 100, -to => 10, -orient        => 'horizontal', -background => 'black', -troughcolor=>  'black', -showvalue => 0,
                -length => 374,        -command=>\&setbrightness,        )->pack(-side => 'left',-expand => 1);
        $scale->set(100);#Helligkeit auf 100%
        
        #Startbutton SeaClear
        $startsc = $drawmenu->Button(-text => 'SeaClear',-background => 'black',-font => 'Arial 10',-foreground => 'white',-command=>\&seaclear,
                )->pack(-side => 'left',-expand => 1);
        #Exit-Button
        $quit = $drawmenu->Button(-text => 'Quit',-background => 'black',-font => 'Arial 10',-foreground => 'white',-command=>\&quit,
                )->pack(-side => 'left',-expand => 1);
        #Dialog
        
        $dialog = $mw->Dialog(-title => 'Fehlermeldung!',-text => 'Keine GPS-Signal gefunden!',-font => 'Arial 11 bold',
                -background => 'red',-foreground => 'white',-buttons => ['Ok'],);
        
        
        
        $mw->update;
        $mw->protocol(WM_DELETE_WINDOW => \&quit);
        
        $readgps = 1;
        $count = 0;

}
sub initsocat{
        if (qx(pidof socat) ne ''){return}
        my $thread2=threads->new(\&startsocat);
        #Prüfen ob ttyUSB99 vorhanden ist
        do {
                $lsusb = qx(ls $usbvread 2>&1);
                chomp($lsusb);
                $n++;
                }
        until ($lsusb eq $usbvread);
        #print $lsusb;
        system("/usr/bin/sudo /bin/chmod 777 ".$usbvsend);
        system("/usr/bin/sudo /bin/chmod 777 ".$usbvread);
        
        $obv = Device::SerialPort->new($usbvsend);
        $obv->baudrate(4800);
        $obv->parity('none');
        $obv->databits(8);
        $obv->stopbits(1);
        $obv->handshake('none');
        $obv->write_settings or die "no settings\n";
}
sub startsocat{
        system("/usr/bin/sudo /usr/bin/socat pty,link=".$usbvsend.",raw,b4800 pty,link=".$usbvread.",raw,b4800");
}

sub readserial{
        my $s1=qx(ls /dev/ttyUSB0 2>&1);
        chomp($s1);
        if($s1 ne '/dev/ttyUSB0'){
                &msgbox;
                return;
        }
        system('sudo chmod 666 /dev/ttyUSB0');
        my $posid;
        my $kursid;
        $log = 0;
        
        $ob->baudrate(4800);
        $ob->parity('none');
        $ob->databits(8);
        $ob->stopbits(1);
        $ob->handshake('none');
        $ob->write_settings or die "no settings\n";
        
        my $charcount = 0;
        my $line = "";
        my $lat = "";
        my $lon = "";
        my $cog = 0;
        my $result="";
        while($readgps == 1){
                my ($count,$result) = $ob->read(1);
                $charcount += $count;
            if ($result ne "\n"){
                    $line = $line . $result;
            }
            else {
                    my $sc=qx(pidof socat);
                    $obv->write($line) if ($sc ne "");
                    
                    if (index($line,"GPRMC") > 0){
                            
                            my @koords=split(/,/,$line);
                            $koords[3] =~ s/\./,/;
                            $koords[5] =~ s/\./,/;
                            $lat = substr($koords[3],0,2) . " ° " . substr($koords[3],2,5);
                            $lon = substr($koords[5],0,3) . " ° " . substr($koords[5],3,5);
                            $lat = $lat . " " . $koords[4];
                            $lon = $lon . " " . $koords[6];
                                $cog = $koords[8];
                                $log= $koords[7];
                                $time=$koords[1];
                    }
                    #Datum und Zeit aktualisieren
                    if (index($line,"GPZDA") > 0){
                            &showdate($line);
                    }
                    #Anzahl Satelliten
                    if (index($line,"GPGGA") > 0){
                            &showsats($line);
                    }
                    $pos = $lat . "     " . $lon;
                    $kurs = int($cog);
                    $line = "";
                    #Kurs aktualisieren
                        $drawpos->dchars('kurs',0,10);
                    $drawpos->insert('kurs',0, 'Kurs : ' . $kurs . '°');
                    #Position aktualisieren
                    $drawpos->dchars('posi',0,50);
                    $drawpos->insert('posi',0, $pos);
                    #Kompass aktualisieren
                    if($move==1){&movecompass($kurs)};
                    #LOG aktualisieren
                    if($log > 0){
                            &movelog($log);
                    };
                    #SeaClear-Button aktualisieren
                    if($move==1){
                            my $sc=qx(pidof $seaclear);
                            if ($sc ne ""){$startsc->configure(-text=>'Running',-background => 'green');}
                            else{$startsc->configure(-text=>'SeaClear',-background => 'black')}
                    }
                    select(undef, undef, undef, 0.3);
                    $mw->update;
                    }
         }
}
sub movecompass{
                my $kurs = shift;
                if ($kurs == $kursalt){return}
                if ($kurs > $kursalt){
                        if(abs($kurs-$kursalt)<=180){
                                for ($n=$kursalt;$n<=$kurs;$n++){
                                        if($move==1){
                                                &clearcompass ;
                                                &showcompass($n);
                                                $mw->update;
                                        }
                                }
                        }
                        else{
                                for ($n=$kursalt;$n>=$kurs-360;$n--){
                                        if($move==1){
                                                &clearcompass;
                                                &showcompass($n);
                                                $mw->update;
                                        }
                                }
                        }
                }
                else{
                        if(abs($kurs-$kursalt)<180){
                                for ($n=$kursalt;$n>=$kurs;$n--){
                                        if($move==1){
                                                &clearcompass;
                                                &showcompass($n);
                                                $mw->update;
                                        }
                                }
                        }
                        else{
                                
                                for ($n=$kursalt;$n<=360+$kurs;$n++){
                                        if($move==1){
                                                &clearcompass;
                                                my $k = $n;
                                                if($n>=360){$k=$n-360}
                                                &showcompass($k);
                                                $mw->update;
                                        }
                                }
                        }
                }
                $mw->update if($move==1);
                $kursalt = $kurs;
}


sub showcompass{
        if($move==0){return}
        my $kurs = shift;
        my $text;
        my $range=46;        
        for ($i=$kurs-$range;$i<=$kurs+$range;$i++) {
                my $numeralRadius = 0.85 * $radius;
                my $angle = $i -90 - $kurs;
            $angle = $angle * 3.14159 / 180  ;
        my $x = $center_x +cos($angle)*$numeralRadius ;
            my $y = $center_y + sin($angle)*$numeralRadius ;
                
                if ($i % 10 == 0){
                        if ($i < 0){$text= 360 + $i}
                        elsif ($i > 360){$text= $i - 360}
                        else{$text = $i}
                        $drawcompass->createText( $x, $y,-fill =>  'white',-text => $text,-font => 'Arial 12',-tags=>'compmoves');
                }
                if ($i % 45 == 0){
                        $x = $center_x + cos($angle)*($numeralRadius * 0.85);
                    $y = $center_y + sin($angle)*($numeralRadius * 0.85);
                        if($i==0||$i==360){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "N",-font => 'Arial 24',-tags=>'compmoves');}
                        if($i==45||$i==405){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "NO",-font => 'Arial 16',-tags=>'compmoves');}
                        if($i==90){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "O",-font => 'Arial 24',-tags=>'compmoves');}
                        if($i==135){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "SO",-font => 'Arial 16',-tags=>'compmoves');}
                        if(abs($i)==180){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "S",-font => 'Arial 24',-tags=>'compmoves');}
                        if($i==225||$i==-135){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "SW",-font => 'Arial 16',-tags=>'compmoves');}
                        if($i==270||$i==-90){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "W",-font => 'Arial 24',-tags=>'compmoves');}
                        if($i==315||$i==-45){$drawcompass->createText( $x, $y,-fill =>  'white',-text => "NW",-font => 'Arial 16',-tags=>'compmoves');}
                }
                        #Kleine Teilstriche
                if ($i % 2 == 0){
                    $x = $center_x + cos($angle)*($numeralRadius * 1.13);
                    $y = $center_y + sin($angle)*($numeralRadius * 1.13);
                    my $x2 = $center_x +cos($angle)*($radius) ;
                    my $y2 = $center_y + sin($angle)*($radius);
                        $drawcompass->createLine( $x, $y,  $x2 , $y2 , -fill  => 'white',-width => 2,,-tags=>'compmoves');
            }
            #Große Teilstriche
            if ($i % 10 == 0){
                    $x = $center_x + cos($angle)*($numeralRadius * 1.1);
                    $y = $center_y + sin($angle)*($numeralRadius * 1.1);
                    my $x2 = $center_x +cos($angle)*($radius) ;
                    my $y2 = $center_y + sin($angle)*($radius);
                        $drawcompass->createLine( $x, $y,  $x2 , $y2 , -fill  => 'white', -width => 4,,-tags=>'compmoves');
            }
        }
        
}
sub movelog{
        if($move==0){return}
        
        my $log = shift;
        $log =($log*40)+16;
        my $y = 50;
        my $y2 = 80;
        $drawlog->delete('logzeiger');
        $drawlog->createLine( $log, $y-30, $log , $y2,-fill  => 'red', -width => 4,-tags=>'logzeiger');
}
sub showlog{
        my $breite = 2 * $center_x; #(500)
        my $range=120;
        my $bigstep = int($breite/$range);
        my $x = 4 * $bigstep;
        my $y = 50;
        my $y2 = 80;
        $drawlog->createText( $center_x+6, $y2-40, -fill => 'white', -text => 'Speed over ground (kn)', -font => 'Arial 9', );
        for ($i=0;$i<=$range;$i++){
                if($i % 10 == 0){
                        $drawlog->createLine( $x+$i*$bigstep, $y, $x+$i*$bigstep , $y2,-fill  => 'white', -width => 3,);
                        $drawlog->createText( $x+$i*$bigstep, $y2-55, -fill => 'white', -text => $i/10, -font => 'Arial 12', -tags => 'log',);
                        }
                if($i % 5 == 0){
                        #$drawlog->createText( $x+$i*$bigstep, $y2-25, -fill => 'white', -text => 5, -font => 'Arial 8', -tags => 'log',);
                        $drawlog->createLine( $x+$i*$bigstep, $y +10 , $x+$i*$bigstep , $y2,-fill  => 'white', -width => 1,);
                        }
                $drawlog->createLine( $x+$i*$bigstep, $y +20 , $x+$i*$bigstep , $y2,-fill  => 'white', -width => 1,);                
                }
        $drawlog->createLine( $x, $y-30, $x , $y2,-fill  => 'red', -width => 4,-tags=>'logzeiger');
        
}
sub showdate{
        my $dt = shift;
        my $mez;
        my $datetime;
        my @datetime=split(/,/,$dt);
        if ($datetime[4] ne "" and length($datetime[4])==4){
        #Beginn Sommerzeit letzter Sonntag im März
                $date = DateTime->last_day_of_month( year => $datetime[4] , month => 3 ) ;
                while ( $date->dow != 7 ) {
                    $date = $date->subtract( days => 1 ) ;
                }
                my $sobegin = $date->ymd;
                #Ende Sommerzeit letzter Sonntag im Oktober
                $date = DateTime->last_day_of_month( year => $datetime[4] , month => 10 ) ;
                while ( $date->dow != 7 ) {
                    $date = $date->subtract( days => 1 ) ;
                }
                my $soend = $date->ymd;
                $date=$datetime[4]."-".$datetime[3]."-".$datetime[2];
                #Ist Sommerzeit?
                if ($date ge $sobegin and $date le $soend){
                        $mez=(substr($datetime[1],0,2))+2;
                        }
                else{
                        $mez=(substr($datetime[1],0,2))+1;
                        }
                $date=$datetime[2] . "." . $datetime[3] . "." . $datetime[4];
                $time=$mez.":".substr($datetime[1],2,2).":".substr($datetime[1],4,2);
                #Aktualisierung
                $drawcompass->dchars('date',0,50);
                $drawcompass->insert('date',0,$date);
                $drawcompass->dchars('time',0,50);
                $drawcompass->insert('time',0,$time.' MEZ');
        }
}
sub showsats{
        my $st = shift;
        my @sats=split(/,/,$st);
        if ($sats[7] =~ /\d+?$/) {
                $drawcompass->dchars('sats',0,50);
                $drawcompass->insert('sats',0,'Satelliten: '.$sats[7]);
                $drawcompass->dchars('quality',0,50);
                $drawcompass->insert('quality',0,'Qualität: '.$sats[6]);
        }
}
sub seaclear{
        my $sc=qx(pidof $seaclear);
        print $sc;
        if ($sc ne ""){
                qx(kill -9 $sc);
                $sc=qx(pidof wineserver);
                qx(kill -9 $sc);
                $sc=qx(pidof socat);
                qx(sudo kill -9 $sc);
        }
        else{
                &initsocat;
                $thread1=threads->new(\&startseaclear);
                my $thread3=threads->new(\&startcpulimit);
                }
}
sub startseaclear{
        qx(wine $seaclear 2>&1);
        }
sub startcpulimit{
        my $pidwineserver = '';
        while($pidwineserver eq ''){
                $pidwineserver = qx(pidof wineserver);
                if ($pidwineserver ne ''){
                        system('cpulimit -l '.$cpulimit.' -b -p '.$pidwineserver);
                }
        sleep(1);
        }
}
sub clearcompass{
        if($move==1){
                $drawcompass->delete('compmoves');
        }
}
sub setbrightness{
        $brightness = ($scale->get())*0.01;
        my $br = qx(xrandr -q | grep " connected");
        @br=split(/\n/,$br);
        my $screen0 = $br[0];
        my $screen1 = $br[1];
        @br=split(/ /,$screen0);
        $screen0 =$br[0];
        if($screen1 ne ""){@br=split(/ /,$screen1)}
        $screen1 =$br[0];
        if($screen1 ne ""){
                $br = qx(xrandr --output $screen1 --brightness $brightness);
        }
        $br = qx(xrandr --output $screen0 --brightness $brightness);
}
sub msgbox{
        if( my $response = $dialog->Show() ) {
                        &quit;
                }else{
                        print "Der Dialog wurde nicht über einen der Buttons beantwortet.";
                }
        
}
sub quit{
        #SeaClear killen
        $readgps=0;
        $move=0;
        my $sc=qx(pidof $seaclear);
        if ($sc ne ""){qx(kill -9 $sc)}
        sleep(1);
        $sc=qx(pidof wineserver);
        if ($sc ne ""){qx(kill -9 $sc)}
        
        sleep(1);
        #Socat killen
        $sc=qx(pidof socat);
        if ($sc ne ""){qx(sudo kill -9 $sc)}
        if(qx(ls /dev/ttyUSB99 2>&1) eq '/dev/ttyUSB99'){
                system("/usr/bin/sudo /bin/rm ".$usbvsend." ".$usbvread);
        }
        $mw->destroy;
}