Accueil > Documentation technique > télécommunications > temps reel sur IP
temps reel sur IP
par
La transmission des corrections d’une station de base vers un récepteur mobile se fait traditionnellement sur une liaison série. Les récepteurs actuels permettent de le faire sur une liaison réseau. Cela simplifie beaucoup de questions matérielles (en particulier parce qu’un seul câble réseau peut servir à plusieurs communications simultanément) mais nécessite plus de connaissance des protocoles et outils réseau. Cet article propose une façon de faire passer les corrections sur IP sans utiliser les outils ntrip.
Il y a une différence essentielle entre la solution par liaison série et celle par liaison IP :
La liaison série a toujours été « point à point » alors que le protocole Ethernet considère que tout le monde parle sur le même support. Alors que la station de base peut diffuser ses corrections en continu sur un port série sans se soucier de savoir si quelqu’un écoute, il n’est pas question de polluer un réseau local avec des messages « diffusés à tous » (broadcast) pour satisfaire un hypothétique récepteur mobile qui écouterait sur ce réseau. Cela signifie qu’il faut venir se connecter sur la station de base pour qu’elle émette ses corrections vers son client.
Le fait de devoir se connecter au récepteur mobile pour lui envoyer les corrections semble plus naturel. Mais il apparaît alors clairement que, pour relier base et mobile, il faut une « tierce machine » qui lance la connexion vers les deux autres et les met ensuite en relation. L’objet de cet article est de donner des éléments pour arriver à cela sans trop de difficultés.
Si la connexion vers un récepteur Trimble NetRS ou NetR5 se fait facilement, celle vers un récepteur Topcon GB1000 est plus délicate car elle nécessite un login.
Le terme technique qui va revenir sans arrêt (et que je ne me vois traduire en Français) est « socket ». C’est un tuyau de communication bi-directionnel qui n’a besoin, pour être défini, que des adresses IP des machines à relier et du numéro du port sur lequel il est connecté.
configuration de la station de base Trimble [1].
La première étape consiste à indiquer à la station quel type de message elle doit diffuser et sur quel port. Comme nous dialoguons avec un récepteur mobile de marque Topcon, nous ne pouvons utiliser le message RT17 propre à Trimble. Nous allons d’abord travailler avec le message standard CMR.
Ici, notre NetR5, d’adresse IP 200.0.1.7 fournira le message CMR Ã qui se connectera sur son port 5017 en TCP.
Pour tester le comportement de cette station, nous pouvons utiliser l’outil netcat
. C’est un très bon outil pédagogique pour comprendre le fonctionnement des sockets. Dans sa forme la plus simple, il va créer une socket entre la machine indiquée et le terminal d’où on l’a lancé.
Il est beaucoup plus simple de comprendre ce qui se passe en le faisant qu’en regardant la copie d’écran ci-dessus car on voit alors les messages de correction s’afficher au fur et à mesure.
On notera la présence de retours à la ligne dont nous reparlerons plus loin. A remarquer également le « prompt » bizarre après l’interruption de netcat
, dà » au passage, dans le message CMR, de codes interprétés comme des caractères spéciaux par le terminal qui a changé sa configuration en conséquence. Le plus simple reste de fermer ce terminal et d’en ouvrir un autre pour continuer...
configuration du récepteur mobile GB1000
Nous conseillons vivement l’utilisation de pccdu.exe
pour commencer. Avec l’habitude la mise en configuration pourra se faire sous GRIL.
Il faut commencer par configurer un des logins réseau (ici « d ») du récepteur pour accepter les corrections en entrée :
Avec un « sniffer » (dans le cas où le dialogue pccdu.exe
- récepteur se fait par IP) on voit passer :
set,/par/dev/tcp/d/imode,cmr
On en profite pour vérifier les paramètres de la connexion telnet (c’est également faisable à partir du clavier du GB1000). On se souvient que le port telnet par défaut du GB1000 est le 8002 (au lieu de 23 sur un système Unix standard) et qu’il accepte quatre connexions simultanées pour les utilisateurs « a », « b » « c » et « d ».
On utilise l’onglet « rover » pour indiquer au GB1000 qu’il est un mobile. Ici je lui ai dit de faire du RTK avec des ambiguïtés flottantes. Il calculera sa position en différentiel quand il le pourra. Il faut que la source des corrections soit « any », car seules les liaisons séries sont prévues dans la liste déroulante.
On voit passer, entre autres, sur le « sniffer » :
set,/par/pos/mode/cur,pf
set,/par/pos/mode/cd,on
set,/par/pos/pd/port,any
En revanche, si nous utilisons netcat
, comme avec le NetR5, pour observer ce qui se passe sur le port en question, nous voyons tout de suite un problème si nous nous contentons de relier la socket base à la socket mobile :
Le GB1000 se comporte comme avec un telnet
et il faut rentrer le login et le mot de passe à la main. J’ai essayé de « tromper » le GB1000 en chaînant une deuxième socket à la première pour effectuer la procédure de login, puis de tuer cette seconde socket pour pouvoir raccorder alors la socket base à la socket mobile. Mais tuer la seconde socket entraîne une fermeture de la session telnet
et un nouveau chaînage de socket amène une nouvelle demande d’identification...
Cela montre qu’on ne peut pas échapper à l’écriture d’un petit programme.
Relier les sockets
Tout d’abord, l’utilitaire netcat
, en dépit de ses possibilités, n’est pas suffisant pour répondre à notre besoin. Nous allons devoir nous tourner vers un autre utililtaire, plus rarement disponible de base sur les distributions Linux, mais généralement prévu dans les paquetages additionnels : socat
A partir de deux fenetres differentes nous lançons
socat tcp-listen:14000,fork tcp:200.0.1.7:5017
d’un côté (le port 14000 de la machine locale fournira les corrections issues du port 5017 du NetR5 en 200.0.1.7),
et
socat tcp-listen:14001,fork tcp:200.0.1.14:8002
de l’autre (une connexion sur le port 14001 de la machine locale mettra en relation avec le GB1000 en 200.0.1.14).
Comment relier les deux avec une procédure d’autentification ?
Je propose un petit programme perl qui ne nécessite pas de connaître le perl pour être compris, contrairement à des programmes C que j’ai vus, qui fonctionnent très bien, mais qui manipulent les sockets à très bas niveau et font donc appel à des fonctions ésotériques (« primitives » est le terme exact dans le monde Unix) pour le néophyte. La puissance de perl réside dans ses modules (annoncés en début de programme par l’instruction use
) qui créent un habillage sympathique autour des méchantes fonctions C. Ici nous aurons besoin d’un module présent d’office dans toutes les distributions que j’ai rencontrées, IO::Socket.
Pour ne pas perdre le lecteur dans des ouvertures/lectures/fermetures de fichiers de configuration, j’ai intégré les couples login/mot de passe dans le programme lui-même.
Je n’ai pas pu m’empêcher de laisser le module Readonly comme incitation aux bonnes pratiques d’écriture d’un programme perl, mais il n’ajoute rien à notre démonstration technique.
Les seules instructions ésotériques sont les deux déclarations de socket
avec affichage du code d’erreur et arrêt du programme en cas de problème, et l’« autoflush » qui évite la rétention d’information dans le tube de communication (« bufferization »).
#!/usr/bin/perl -w
# base2rover.pl O.Charade 2008 May 29
#
#
use strict;
use Readonly;
use IO::Socket;
#
Readonly my $USAGE => << 'END_USAGE';
usage: connect.pl local_port_base local_port_rover
END_USAGE
die( "$USAGE\n") if ($#ARGV != 2 );
my $PORTNO = $ARGV[0];
my $PORTN1 = $ARGV[1];
my $base = IO::Socket::INET->new( PeerPort => $PORTNO,
PeerHost => '127.0.0.1',
Proto => 'tcp',
) or die("$!");
my $rover = IO::Socket::INET->new( PeerPort => $PORTN1,
PeerHost => '127.0.0.1',
Proto => 'tcp',
) or die("$!");
my $log_rover = 'd';
my $pwd_rover = 'T224398';
$base->autoflush(1); # don't keep anything in buffer!
$rover->autoflush(1); # don't keep anything in buffer!
print $rover "$log_rover\n"; # login
print $rover "$pwd_rover\n";
my $stream;
while ( defined($stream = <$base>) ){
print $rover $stream ;
}
Le login sur le GB1000 se limite à une écriture sur la socket
.
Tout le travail de transfert se fait dans la boucle while
où il est simplement écrit que ce qui sort du tuyau $base
est immédiatement mis dans le tuyau $rover
.
A quoi voit-on que ça marche ? Sur pccdu, l’indication « standalone » est remplacée par « RTK float » (mais elle revient de temps en temps quand la correction n’est pas arrivée dans les temps ou n’a pas été émise). Sur l’écran du GB1000, le symbole du lien radio apparaît à côté du nombre de satellite.
Le message RTCM 2.X
Configurons maintenant un récepteur NetRS (d’adresse IP 200.0.1.2) pour émettre un message de type RTCM sur le port 5019, toujours en tcp (la documentation du NetRS précise que dans le cas d’une connexion UDP, le client doit régulièrement émettre un message « keep alive » vers le serveur, ce que nous ne souhaitons devoir gérer en plus).
Utilisons netcat
pour vérifier que ça marche comme nous le pensons :
Nous constatons (toujours plus facilement en le faisant qu’en regardant la capture d’écran ci-dessus) l’ABSENCE TOTALE de caractères de fin de ligne. Voilà qui va poser un gros problème à mon programme perl :
La lecture du tuyau $base
n’est « activée » que par une fin de ligne... Il m’a fallu du temps pour comprendre ce qui se passait. Après de multiples essais, alors que mon programme tournait sans que je voie quoique ce soit aller vers le mobile, j’ai tué la socket
vers la base. Immédiatement tout un tas de corrections sont passées d’un seul coup vers le mobile : il s’agissait de toutes les corrections accumulées depuis le lancement du programme à l’entrée de la socket
et qui attendaient un caractère de fin de ligne pour entrer dans le tuyau...
Configurons le GB1000 pour accepter le message RTCM (set,/par/dev/tcp/d/imode,rtcm
),
et modifions le mode de lecture du programme perl.
while ( sysread $base,$stream,1) ){
syswrite $rover,$stream,1 ;
}
Il n’y que ça à changer : on remplace les traditionnelles instructions de lecture/écriture par les appels système au plus bas niveau, pour lesquels on doit préciser le nombre d’octets à lire (ici 1 car je n’ai pas voulu m’embêter à rechercher le format du message RTCM). Et ça marche ! Ca marche d’ailleurs également dans le cas du message CMR, mais je trouvais moins pédagogique de donner immédiatement cette solution où l’on fait appel à des fonctions qui commencent à mettre le lecteur mal à l’aise...
post scriptum :
Dans la famille RTCM, Je n’ai parlé que du message RTCM 2.X car c’est celui avec lequel j’ai eu le plus de mal. Le message RTCM 3 issu d’un NetR5 contient apparemment des fins de ligne. Son utilisation ne présente pas de difficulté nouvelle.
Je n’ai pas décrit le cas où un GB1000 est également en station de base : il suffit de rajouter le login correspondant dans le programme et ça marche immédiatement.
[1] Le récepteur NetRS sur lequel je travaillais est tombé en panne pendant la rédaction de cet article. Trimble France a mis à ma disposition un récepteur NetR5 pour finir mes tests, ce qui explique les changements de type de récepteur en cours d’article.