Introduction

This section aims to introduce the basic usage, and general concepts of the package.

Communication

The primary way of communication with surveying instruments is through a direct serial connection (RS232). This is available on almost all products. Newer equipment might also come with built-in, or attachable bluetooth connection capabilities.

Communication related definitions can be found in the communication module.

A utility function can be used to open the serial connection, that works similarly to the open() function of the standard library.

Creating connection with the utility function
1
2
3
4
5
from geocompy.communication import open_serial


with open_serial("COM1", timeout=15) as com:
    com.send("some message")

See also

Communication methods are discussed in more detail in Connections.

Protocols

The GeoComPy package (as the name suggests) primarily built around the GeoCOM command protocol. This was developed by Leica and is available on a wide range of their products. For some older instrument types, that do not support GeoCOM, older systems (like GSI Online) might be implemented instead. All serial communication based protocols are fundamentally synchronous systems, consisting of request-response pairs.

Note

Leica stopped selling GeoCOM robotic licenses for their TPS1200 series instruments in 2019. Newer instruments have a more complicated licensing scheme.

The primary goal is to provide methods to call all known GeoCOM commands on the supported instruments. These “low-level” commands can then be used to build more complex applications.

GeoCOM

GeoCOM enabled instruments can communicate with the ASCII version of the protocol through a stable connection. Each command is a serialized RPC (Remote Procedure Call) request, that specifies the code of the procedure to run, and supplies the necessary arguments. The reply is a serialized RPC response message, containing the return parameters.

GeoCOM exchange example
%R1Q,9029:1,1,0 # RPC 9029, prism search in window
%R1P,0,0:0      # Standard OK response

All the supported instruments follow a similar API structure. The instrument object implements the generic request functions. The actual GeoCOM commands are available through their respective subsystems.

The connection to an instrument can be easily set up through a serial connection. The connection is tested during the initialization, and some communication parameters are syncronized.

Initializing instrument connection with GeoCOM
1
2
3
4
5
from geocompy import GeoCom, open_serial


with open_serial("COM1", timeout=10) as com:
    tps = GeoCom(com)

Note

If the instrument is not turned on when the connection is initiated, the process will try to wake it up. Since some instruments must be manually put into GeoCOM mode, the initialization might not be successful from a completely shutdown state.

Once the connection is verified, the commands can be executed through the various subsystems.

Querying the system software version through Central Services
1
2
resp = tps.csv.get_firmware_version()
print(resp)  # GeoComResponse(CSV_GetSWVersion) com: OK, rpc: OK...

All GeoCOM commands return a GeoComResponse object, that encapsulates the return codes, as well as the optional returned paramters.

Tip

The complete list of available commands and their documentations are available in their respective API documentation categories.

GSI Online

The GSI Online protocol is a command system that is older than GeoCOM. Many older instruments only support this system. Some support both (e.g. TPS1100 series).

The commands fall into two groups:

  • instrument settings (CONF and SET commands)

  • measurements (GET and PUT commands)

Instrument settings are set and queried with the SET and CONF commands. The values are communicated with simple enumerations of the valid settings.

GSI Online settings exchange example
CONF/30   # Query command
0030/0001 # Response

SET/30/2  # Setting beeping to loud
?         # Success confirmation

Measurement related PUT and GET commands on the other hand use GSI data words to exchange the necessary information.

GSI Online measurements exchange example
GET/M/WI11                # Query current point ID
11....+000000A1           # Response if format is GSI8
*11....+00000000000000A1  # Response if format is GSI16

PUT/11....+000000A2       # Setting new point ID
?                         # Success confirmation

The GSI Online based implementations mainly consist of 3 parts. The instrument object implements the basic request functions. The settings and the measurements subsystems provide the individual commands.

The connection to an instrument is identical to the GeoCOM versions. The connection is tested during the initialization, and some communication parameters are syncronized.

Initializing instrument connection with GSI Online
1
2
3
4
5
from geocompy import GsiOnlineDNA, open_serial


with open_serial("COM1", timeout=10) as com:
    level = GsiOnlineDNA(com)

Note

If the instrument is not turned on when the connection is initiated, the process will try to wake it up.

Once the connection is live, the commands can be executed.

Turning off beeping and getting a staff reading
1
2
3
level.settings.set_beep(level.settings.BEEPINTENSITY.OFF)
resp = level.measurements.get_reading()
print(resp)  # GsiOnlineResponse(Reading) success, value: ...

All GSI Online commands return a GsiOnlineResponse object, that encapsulates command metadata and the result of the request.

Tip

The complete list of available commands and their documentations are available in their respective API documentation categories.

Logging

For debugging purposes it might be very useful to have a log of certain events, errors and debug information. To support this, the instrument classes all take an optional Logger object, that they use to log specific events.

Passing a console logger
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sys import stdout
from logging import getLogger, DEBUG, StreamHandler

from geocompy import GsiOnlineDNA, open_serial


logger = getLogger("TPS")
logger.addHandler(StreamHandler(stdout))
logger.setLevel(DEBUG)
with open_serial("COM1", timeout=15) as com:
    level = GsiOnlineDNA(com, logger=logger)

Some examples of the information logged on various levels:

  • connection start

  • instrument wake up

  • instrument shutdown

  • all unexpected exceptions

  • all command responses

Error handling and development

As described in the previous sections, under normal conditions, all commands return response wrapper objects. If an error occured it is indicated by the error code in the response object and/or the lack of parsed parameters. These errors have to be explicitly handled in the application.

Caution

The error codes have descriptive names, that usually give some clue about the nature of the issue. One caveat is, that the response parser returns the UNDEFINED code not just when that was actually received, but also when an unknown error code was received. One example of this is error code 30, which can be seen in the wild, but is not documented anywhere. The response wrapper will contain UNDEFINED in cases like this.

The simplest solution is to check if the error code is simply OK:

response = tps.ftr.setup_listing()
if response.error != GeoComCode.OK:
    # handle error

When static type checkers are involved, it might be necessary to check for both the error code and the existence of the parsed parameters.

response = tps.ftr.setup_listing()
if response.error != GeoComCode.OK or response.params is not None:
    # handle error

Different commands return different errors signaling the various issues. Some errors might be recoverable, others might not be.

response = tps.aut.fine_adjust(1, 1)
if response.error == GeoComCode.AUT_NOT_ENABLED:
    response = tps.aus.switch_user_atr(True)
    if response.error == GeoComCode.OK:
        reponse = tps.aut.fine_adjust(1, 1)
    else:
        print("Cannot activate ATR")
        exit(1)

if response.error == GeoComCode.AUT_NO_TARGET:
    response_ps = tps.aut.powersearch_next('CLOCKWISE', True)
    if response_ps.error != GeoComCode.OK:
        print("Could not find target")
        exit(1)
    else:
        response = tps.aut.fine_adjust(1, 1)

if response.error != GeoComCode.OK:
    print("ATR fine adjustment failed, and could not reackquire target")
    exit(1)

Note

The command line programs implemented in the Instrumentman package can be used as reference examples for development.