products:kronos:rtkronos:unicorecomm_gps_rtk_devboard

GPS RTK devboard from Unicorecomm


tags: RTK Unicorecomm, GPS

  1. Débranchez l'alimentation et mettez l'interrupteur d'alimentation en position éteinte (sur la gauche)
  2. Connectez la carte UB4B0 sur la carte de développement HPL-EVK
    • Via port série:
      • Si vous n'avez pas de port RS232, connectez le port RS232 COM3 à un convertisseur RS232↔USB.

La carte utilisé ici est un DFRobot Multiplexer v1.1, connecté sur le port B-232 (fil rouge PC TX → RX pin 3 RS-232, fil orange PC RX ← TX pin 2 RS-232, masse sur pin 5)

  • Via port ethernet:
    • La carte a comme adresse IP 192.168.0.100. Vous pouvez connecter votre ordinateur en direct sur la carte et définir l'adresse IP de votre ordinateur sur un sous-réseau valide (ex: adresse IP de l'ordinateur: 192.1680.42 et masque de sous-réseau 255.255.255.0).
    • Voir les commandes disponible dans le document TCP CONFIG pour changer l'adresse IP ou configurer le DHCP.
  1. Mettez sous tension en glissant l'interrupteur d'alimentation en position allumé (sur la droite)

Vous pouvez maintenant lancer UPrecise (plus récent) ou CDT (ne tient pas compte des satellites en L5) et configurer la connexion sur le port série de votre machine (baudrate 115200) ou sur l'adresse IP 192.168.0.100 si vous êtes en ethernet.

Vous avez aussi la possibilité d'utiliser une console série (putty sous Windows, dterm sous linux par exemple) ou une connexion par telnet sur le port 40000 (telnet 192.168.0.100 40000) si vous êtes connecté par ethernet afin d'envoyer directement des commandes de configuration au module GPS.

Depuis la console UPrecise (ou n'importe quelle moyen de communication avec le GPS), envoyez les commandes suivantes:

Remplacez LAT, LONG et HEIGHT avec les coordonnées connues de la base.

UNLOGALL COM2
FIX NONE
MODE BASE LAT LONG HEIGHT
LOG COM2 RTCM1006 ontime 10
LOG COM2 RTCM1033 ontime 10
LOG COM2 RTCM1074 ontime 1
LOG COM2 RTCM1084 ontime 1
LOG COM2 RTCM1094 ontime 1
LOG COM2 RTCM1124 ontime 1

La ligne 3 permet de configurer les paramètres de calcul automatique de la position. Le format est le suivant:
MODE BASE TIME SECONDS HORIZONTAL VERTICAL

  • HORIZONTAL et VERTICAL correspondent à l'écart type autorisé en latitude/longitude et altitude en mètre;
  • SECONDS correspond au timeout dans le cas où la précision demandé n'est pas atteinte.
UNLOGALL COM2
FIX NONE
MODE BASE TIME 60 1.5 2.5
LOG COM2 RTCM1006 ontime 10
LOG COM2 RTCM1033 ontime 10
LOG COM2 RTCM1074 ontime 1
LOG COM2 RTCM1084 ontime 1
LOG COM2 RTCM1094 ontime 1
LOG COM2 RTCM1124 ontime 1

Sous Linux et OSX, lancez la commande dmesg -w et connectez le port USB afin de voir sur quel port la carte est attribué.

Sur Windows, le format du port est COMx, `x` étant un nombre défini par Windows. Lancez le Gestionnaire de périphérique et branchez le port USB pour repérer le port attribué par Windows

Voici un exemple de code Python utilisant la bibliothèque pyserial pour configurer la carte pour qu'elle transmette sa meilleure position connue toutes les secondes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/python3
# pip install typing pyserial
from typing import NamedTuple, Union
 
import threading
import serial
import re
import datetime
from time import time, sleep
 
 
BestPosition = NamedTuple('BestPosition', [
    ('gps_week', int),
    ('gps_sec', float),
    ('solution_type', str),
    ('position_type', str),
    ('gps_latitude', str),
    ('gps_longitude', str),
    ('gps_altitude', str),
    ('gps_date', str)
])
 
class UB4B0_rover():
 
    def __init__(self, port, baudrate=115200, timeout=3):
        self.serial = serial.Serial(port=port, baudrate=baudrate, timeout=timeout)
        self.lock = threading.Lock()
 
        # Send rover configuration
        self.send_command('UNLOGALL', waitResp=False) # Remove previous logs
        self.send_command('FIX none', waitResp=False) # Remove any previousl fixed position (base station)
        self.send_command('SAVECONFIG', waitResp=False) # Save configuration
 
    def close(self):
        self.serial.close()
 
    def write(self, data: bytes):
        with self.lock:
            self.serial.write(data)
 
    def send_command(self, command: str, waitResp: bool = True) -> str:
        with self.lock:
            # Flush input buffer
            self.serial.reset_input_buffer()
 
            # Send command
            self.serial.write(bytes(command + '\r\n', 'utf-8'))
            # Expected response should be `$command,{command},response: OK*{checksum}\r\n`
            # There is no info how the checksum is calculated, so skip it
            expected_resp = '$command,{command},response: OK*'.format(command=command)
            # Check that the command has been correctly received by the GPS
            resp = self.serial.readline().decode('utf-8')
            if expected_resp not in resp:
                raise ValueError('Invalid reponse, got:\n {}'.format(resp))
            if waitResp == True:
                resp = self.serial.readline().decode('utf-8')
                return resp
 
    def get_best_position(self) -> Union[None, BestPosition]:
        bestpos = self.send_command("LOG BESTPOSA once")
        if bestpos.startswith("#BESTPOSA") is False:
            return None
        if "INSUFFICIENT_OBS" in bestpos:
            return None
 
        # Get every field (separators are ',', ';', '*')
        parser = r"([^,\*;]+)"
        matches = re.findall(parser, bestpos)
        # Example of valid data: "#BESTPOSA,COM2,0,86.0,FINE,1991,402429.800,00000000,929861713,18;SOL_COMPUTED,NARROW_FLOAT,48.58252933494,7.76681014722,144.8847,48.4450,WGS84,0.1256,0.1388,0.3033,"0",0.800,0.000,11,10,10,5,0,00,0,13*d7c1d0b0"
        # Documentation on the BESTPOSA command can be found on the previous command manual
        # TODO: better & safer matching
        if len(matches) is not 32:
            return None
 
        gps_week = int(float(matches[5]))
        gps_sec = float(matches[6])
 
        datetimeformat = "%Y-%m-%dT%H:%M:%S.%f"
        epoch = datetime.datetime.strptime("1980-01-06T00:00:00.000", datetimeformat)
        elapsed = datetime.timedelta(days=gps_week*7, seconds=gps_sec)
        # Warning: the following date doesn't take account of leap seconds! (substract 16 seconds @ 2018-06-11)
        gps_date = datetime.datetime.strftime(epoch + elapsed, datetimeformat)
 
        best_position = BestPosition(
            gps_week      = gps_week,
            gps_sec       = gps_sec,
            solution_type = matches[10],
            position_type = matches[11],
            gps_latitude  = matches[12],
            gps_longitude = matches[13],
            gps_altitude  = matches[14],
            gps_date=gps_date
        )
 
        return best_position
 
if __name__ == '__main__':
    rover = UB4B0_rover(port='/dev/ttyUSB0')
 
    while True:
        t = time()
        try:
            best_position = rover.get_best_position()
            print(best_position)
        except ValueError as e:
            print("Invalid data received: {}".format(e))
 
        # Wait 1 second between two measurements
        # TODO: use PPS signal to check when new position is available
        if time() - t < 1:
            sleep(1 - (time() - t))

  • products/kronos/rtkronos/unicorecomm_gps_rtk_devboard.txt
  • Last modified: 2021/04/04 12:07
  • by manu