#!/usr/bin/env python
"""
.. module:: totalstation.py
:platform: Unix, Windows
:synopsis: Ulyxes - an open source project to drive total stations and
publish observation results. GPL v2.0 license Copyright (C)
2010- Zoltan Siki <siki.zoltan@epito.bme.hu>
.. moduleauthor:: Zoltan Siki <siki.zoltan@epito.bme.hu>,
Daniel Moka <mokadaniel@citromail.hu>
"""
import logging
import time
from instrument import Instrument
from angle import Angle
from trimble5500 import Trimble5500
#try:
# from bluetoothiface import BluetoothIface
#except:
# pass
[docs]
class TotalStation(Instrument):
""" Generic total station instrument
:param name: name of instrument
:param measureUnit: measure unit part of instrument
:param measureIface: interface to physical unit
:param writerUnit: store data, default None
"""
FACE_LEFT = 0
FACE_RIGHT = 1
FACE_AVG = 2
def __init__(self, name, measureUnit, measureIface, writerUnit=None):
""" Constructor
"""
# call super class init
super().__init__(name, measureUnit, measureIface, writerUnit)
if isinstance(measureUnit, Trimble5500):
# change default eol marker for read
measureIface.eomRead = '>'
# self.__class__.add_totalStation(self)
def __str__(self):
return '<{} object from {} module at {} address | MeasureUnit: {} | MeasureInterface: {} >'\
.format(type(self).__name__, self.__module__, hex(id(self)),
self.measureUnit.GetName(), self.measureIface.name)
def __repr__(self):
muString = self.measureUnit.GetName()
muString = muString.replace(' ', '') + '()'
return "{}('{}',{},'{}')".format(type(self).__name__, self.name,
muString, self.measureIface.GetName())
[docs]
def SetPc(self, pc):
""" Set prism constant
:param pc: prism constant [m]
:returns: processed answer from instrument
"""
msg = self.measureUnit.SetPcMsg(pc)
return self._process(msg)
[docs]
def GetPc(self):
""" Get prism constant
:returns: processed answer from instrument
"""
msg = self.measureUnit.GetPcMsg()
return self._process(msg)
[docs]
def SetATR(self, atr):
""" Set ATR on
:param atr: 0/1 ATR off/on
:returns: processed answer from instrument
"""
msg = self.measureUnit.SetATRMsg(atr)
return self._process(msg)
[docs]
def GetATR(self):
""" Get ATR status of instrument
:returns: 0/1 ATR off/on
"""
msg = self.measureUnit.GetATRMsg()
return self._process(msg)
[docs]
def SetPrismType(self, typ):
""" Set prism type
:param typ: prizm type
"""
msg = self.measureUnit.SetPrismTypeMsg(typ)
return self._process(msg)
[docs]
def GetPrismType(self):
""" Get prism type
"""
msg = self.measureUnit.GetPrismTypeMsg()
return self._process(msg)
[docs]
def SetLock(self, lock):
""" Set lock on prism
:param lock: 0/1 lock off/on
:returns: processed answer from instrument
"""
msg = self.measureUnit.SetLockMsg(lock)
return self._process(msg)
[docs]
def GetLock(self):
""" Get lock status
:returns: lock status of the instrument 0/1 on/off
"""
msg = self.measureUnit.GetLockMsg()
return self._process(msg)
[docs]
def LockIn(self):
""" Turn on lock
:returns: empty
"""
msg = self.measureUnit.LockInMsg()
return self._process(msg)
[docs]
def SetAtmCorr(self, valueOfLambda, pres, dryTemp, wetTemp=None):
""" Set atmospheric correction
:param valueOfLambda: instrument specific constant
:param pres: air presure
:param dryTemp: dry temperature
:param wetTemp: wet temperature
"""
if wetTemp is None:
wetTemp = dryTemp - 5.0
msg = self.measureUnit.SetAtmCorrMsg(valueOfLambda, pres, dryTemp,
wetTemp)
return self._process(msg)
[docs]
def GetAtmCorr(self):
""" Get atmospheric correction
:returns: atmospheric corrections (dictionary)
"""
msg = self.measureUnit.GetAtmCorrMsg()
return self._process(msg)
[docs]
def SetRefCorr(self, status, earthRadius, refracticeScale):
""" Set refraction correction
:param status: ???
:param earthRadius: radius of earth
:param refracticeScale: ???
"""
msg = self.measureUnit.SetRefCorrMsg(status, earthRadius,
refracticeScale)
return self._process(msg)
[docs]
def GetRefCorr(self):
""" Get refraction correction
:returns: refraction correction (dictionary)
"""
msg = self.measureUnit.GetRefCorrMsg()
return self._process(msg)
[docs]
def SetStation(self, easting, northing, elevation, ih=0.0):
""" Set station coordinates
:param easting: easting of station
:param northing: northing of station
:param elevation: elevation of station
:param ih: instrument height
:returns: ???
"""
msg = self.measureUnit.SetStationMsg(easting, northing, elevation, ih)
return self._process(msg)
[docs]
def GetStation(self):
""" Get station coordinates
:returns: station coordinates and instrument height (dictionary)
"""
msg = self.measureUnit.GetStationMsg()
return self._process(msg)
[docs]
def SetEDMMode(self, mode):
""" Set EDM mode
:param mode: mode name/id as listed in measure unit
:returns: empty dictionary
"""
msg = self.measureUnit.SetEDMModeMsg(mode)
return self._process(msg)
[docs]
def GetEDMMode(self):
""" Get EDM mode
:returns: actual EDM mode
"""
msg = self.measureUnit.GetEDMModeMsg()
return self._process(msg)
[docs]
def SetOri(self, ori):
""" Set orientation
:param ori: bearing to direction (Angle)
:returns: empty dictionary
"""
# clear previous distance measured
ans = self.Measure('CLEAR')
if 'errCode' in ans:
return ans
msg = self.measureUnit.SetOriMsg(ori)
return self._process(msg)
[docs]
def SetRCS(self, rcs):
""" Remote control
"""
msg = self.measureUnit.SetRCSMsg(rcs)
return self._process(msg)
[docs]
def Move(self, hz, v, atr=0):
""" Rotate instrument to a given direction
:param hz: horizontal direction (Angle)
:param v: zenith (Angle)
:param atr: 0/1 ATR on/off
"""
hz.Positive() # negative angles are not accepted by totalstations
v.Positive()
msg = self.measureUnit.MoveMsg(hz, v, atr)
return self._process(msg)
[docs]
def Measure(self, prg='DEFAULT', incl=0):
""" Measure distance
:param prg: EDM program, DEFAULT is the only reasonable value
:param incl: not used, only for compability
:returns: empty dictionary
"""
if type(prg) is str:
prg = self.measureUnit.edmProg[prg]
msg = self.measureUnit.MeasureMsg(prg, incl)
return self._process(msg)
[docs]
def GetMeasure(self, wait=15000, incl=0):
""" Get measured values
:param wait: waiting time in ms
:param inc: inclination ...
:returns: observations in a dictionary
"""
msg = self.measureUnit.GetMeasureMsg(wait, incl)
i = 0
meas = self._process(msg)
if isinstance(self.measureUnit, Trimble5500):
while 'distance' not in meas and i < 20: # wait for trimble 5500
i += 1
time.sleep(2)
meas = self._process(msg)
return meas
[docs]
def MeasureDistAng(self, prg='DEFAULT'):
""" Measure distance and return observations
:returns: observations in a dictionary
"""
if type(prg) is str:
prg = self.measureUnit.edmProg[prg]
msg = self.measureUnit.MeasureDistAngMsg(prg)
return self._process(msg)
[docs]
def Coords(self, wait=15000, incl=0):
""" Read coordinates from instrument
:param wait: waiting time ms
:param incl: inclination
:returns: coordinates in a dictionary
"""
msg = self.measureUnit.CoordsMsg(wait, incl)
return self._process(msg)
[docs]
def GetAngles(self):
""" Get angles from instrument
:returns: angles in a dictionary
"""
msg = self.measureUnit.GetAnglesMsg()
return self._process(msg)
[docs]
def ClearDistance(self):
""" Clear measured distance on instrument
"""
msg = self.measureUnit.ClearDistanceMsg()
return self._process(msg)
[docs]
def ChangeFace(self):
""" Change face
:returns: empty dictionary
"""
msg = self.measureUnit.ChangeFaceMsg()
if msg is None:
angles = self.GetAngles()
angles['hz'] += Angle(180, 'DEG')
angles['v'] = Angle(360, 'DEG') - angles['v']
return self.Move(angles['hz'], angles['v'])
return self._process(msg)
[docs]
def SetRedLaser(self, on):
""" Set on/off red laser
:param on: 0/1 off/on
:returns: empty dictionary or error
"""
msg = self.measureUnit.SetRedLaserMsg(on)
return self._process(msg)
[docs]
def SetSearchArea(self, hzCenter=None, vCenter=None, \
hzRange=None, vRange=None, on=1):
""" Set range for power search
:param hzCenter: center direction (Angle)
:param vCenter: center direction (Angle)
:param hzRange: horizontal range to search (default full circle) (Angle)
:param vRange: vertical range to search (default 95 degree) (Angle)
:param on: 0/1 off/on
"""
if hzCenter is None or vCenter is None:
angles = self.GetAngles()
if hzCenter is None:
hzCenter = angles['hz']
if vCenter is None:
vCenter = angles['v']
if hzRange is None:
hzRange = Angle(399.9999, 'GON')
if vRange is None:
vRange = Angle(95, 'DEG')
msg = self.measureUnit.SetSearchAreaMsg(hzCenter, vCenter, hzRange,
vRange, on)
return self._process(msg)
[docs]
def PowerSearch(self, direction=1):
""" Start power search
:param direction: 1/-1 clockwise/counter clockwise
:returns: empty list if succesfull
"""
msg = self.measureUnit.PowerSearchMsg(direction)
return self._process(msg)
[docs]
def GetSpiral(self):
""" Get search spiral parameters
:returns: horizontal and vertical range
"""
msg = self.measureUnit.GetSpiralMsg()
return self._process(msg)
[docs]
def SetSpiral(self, dRangeHz, dRangeV):
""" Set search spiral parameters
:param dRangeHz: horizontal range (Angle)
:param dRangeV: vertical range (Angle)
"""
msg = self.measureUnit.SetSpiralMsg(dRangeHz, dRangeV)
return self._process(msg)
[docs]
def SearchTarget(self):
""" Search target
:returns: TODO
"""
msg = self.measureUnit.SearchTargetMsg()
return self._process(msg)
[docs]
def SwitchOn(self, mode=1):
""" Switch on or wake up instrument and change to remote control
:param mode: 0/1 local/remote mode
:returns: empty list if successful, timeout may occure
"""
msg = self.measureUnit.SwitchOnMsg(mode)
return self._process(msg)
[docs]
def SwitchOff(self):
""" Switch off instrument
:param mode: 0/1 power down/sleep state
:returns: processed answer from instrument
"""
msg = self.measureUnit.SwitchOffMsg()
return self._process(msg)
[docs]
def GetInstrumentNo(self):
""" Get instrument factory number
:returns: processed answer from instrument
"""
msg = self.measureUnit.GetInstrumentNoMsg()
return self._process(msg)
[docs]
def GetInstrumentName(self):
""" Get instrument name
:returns: processed answer from instrument
"""
msg = self.measureUnit.GetInstrumentNameMsg()
return self._process(msg)
[docs]
def GetInternalTemperature(self):
""" Get instrument internal temperature
:returns: processed answer from instrument
"""
msg = self.measureUnit.GetInternalTemperatureMsg()
return self._process(msg)
[docs]
def GetFace(self):
""" Get face left or face right
:returns: 0/1 face left/face right in a dictionary or None in case of error
"""
a = self.GetAngles()
if 'v' in a:
if a['v'].GetAngle('GON') < 200:
face = self.FACE_LEFT
else:
face = self.FACE_RIGHT
return {'face': face}
logging.error(" Getangles failed")
return None
[docs]
def MoveRel(self, hz_rel, v_rel, atr=0):
""" Rotate the instrument relative to actual direction
:param hz_rel: relative horizontal rotation (Angle)
:param v_rel: relative zenith rotation (Angle)
:param atr: 0/1 atr on/off
"""
#get the actual direction
msg = self.measureUnit.GetAnglesMsg()
res = self._process(msg)
if 'hz' in res and 'v' in res:
return self.Move(res['hz'] + hz_rel, res['v'] + v_rel, atr)
return None
if __name__ == "__main__":
from echowriter import EchoWriter
from serialiface import SerialIface
from axis10 import Axis10
#from leicatps1200 import LeicaTPS1200
#from leicatcra1100 import LeicaTCRA1100
#from leicatca1800 import LeicaTCA1800
logging.getLogger().setLevel(logging.DEBUG)
mu = Axis10()
#mu = LeicaTPS1200()
#mu = LeicaTCA1800()
#mu = Trimble5500()
iface = SerialIface("rs-232", "/dev/ttyUSB0")
#iface = BluetoothIface('test', '00:12:F3:04:ED:06', 1)
wrt = EchoWriter()
ts = TotalStation("Leica", mu, iface, wrt)
#ts.SetStation(10.0, 20., 30., 1.0)
ts.SetStation(0.0, 0.0, 0.0, 0.0)
#print(ts.GetStation())
#print(ts.GetInstrumentNo())
#ts.GetInstrumentName()
#ts.SetEDMMode(ts.measureUnit.edmModes['RLSTANDARD'])
#ts.SetPc(0.0068)
#print(ts.GetPc())
#ts.PowerSearch()
#m = ts.GetEDMMode()
#angs = ts.GetAngles()
ts.SetATR(1)
#ts.Move(Angle(90, 'DEG'), Angle(85, 'DEG'))
#ts.Move(angs['hz'], angs['v'], 1)
ts.Move(Angle(0.0), Angle("82-28-30", "DMS"), 1)
#ts.MoveRel(Angle(0.0), Angle(0.0), 1)
ts.Measure()
#ts.SetEDMMode(ts.measureUnit.edmModes['RLSTANDARD'])
#ts.Measure()
meas = ts.GetMeasure()
#while 'distance' not in meas:
#time.sleep(5)
#meas = ts.GetMeasure()
#print(meas)
#ts.SwitchOff()