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:

#!/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