Skip to content
Snippets Groups Projects
Commit 922775f9 authored by Ashwin Rao's avatar Ashwin Rao
Browse files

Initial commit

parent 533c9cbe
No related branches found
No related tags found
No related merge requests found
This folder contains the script to parse the log files and plot the results used in the paper
The folder contains the client which receives the data from the mqtt broker of the rtcm3\_relay.
## Python environment for rtcm3\_client
This step is similar to what is required for the rtcm3\_relay
Create a python environment where paho-mqtt is installed. This code was tested using python 3.8
Create a venv folder in this directory.
```
python3.8 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
- You might see some errors about bdist\_wheel which can be ignored.
## Command
```
timeout <duration for which to log the results> python rtcm_client.py -h <hostname or IP address> -p <port number> -s <prefix for logs>
```
import paho.mqtt.client as mqtt
import json
import base64
import socket
import signal
import threading
import datetime
import argparse
# Provide the hostname and port number here of the broker.
#MQTTBROKER_HOSTNAME = "86.50.17.54"
#MQTTBROKER_HOSTNAME = "localhost"
#MQTTBROKER_PORT = 8883
# The topic used to subscribe at the broker.
MQTT_RTCM3_TOPIC = "rtcm3"
# The name of the client
MQTT_RTCM3_CLIENT = "rtcm3client"
# Preamble used.
RTCM3_PREAMBLE = b'\xd3'
class MQTTSubscriber:
mqtt_client = None
event_semaphore = None
rtcm3_op_stream = None
timelog_stream = None
"""
create an MQTT client that connects to the broker
"""
def __init__(self, scenario_name, broker_hostname, broker_port):
# Create a log file to save the logs.
self.rtcm3_op_stream = open(scenario_name+"-rtrcv.rtcm3", "wb")
self.timelog_stream = open(scenario_name + "-timestamps.txt", "w")
# Create the client and provide the handlers for the events
self.mqtt_client = mqtt.Client(client_id=MQTT_RTCM3_CLIENT, clean_session=True, userdata=None, transport='tcp')
self.mqtt_client.on_connect = self._mqtt_connect
self.mqtt_client.on_disconnect = self._mqtt_disconnect
self.mqtt_client.on_message = self.mqtt_message_recv
# Connect the client to the broker and subscribed to the topics.
self.mqtt_client.connect(broker_hostname, broker_port)
self.mqtt_client.subscribe(topic=MQTT_RTCM3_TOPIC)
print("Connected to MQTT Broker")
# Create an event semaphore used to indicate that the mqtt client is running.
self.event_semaphore = threading.Semaphore(0)
# Specify the signal handlers.
signal.signal(signal.SIGINT, self.handle_exit)
signal.signal(signal.SIGTERM, self.handle_exit)
"""
Debug messages to show when connected
"""
def _mqtt_connect(self, client, obj, flags, rc):
#self.logger.debug("rc: %s",str(rc))
return
"""
Do a clean disconnect
"""
def _mqtt_disconnect(self, client, userdata, rc=0):
client.loop_stop()
return
def mqtt_message_recv(self, client, obj, msg):
if msg.topic != MQTT_RTCM3_TOPIC:
return
try:
payload = json.loads(msg.payload)
rtcm3_data = payload['rtcm3']
rtcm3_data = base64.b64decode(rtcm3_data)
#print(rtcm3_data)
self.rtcm3_op_stream.write(rtcm3_data)
timestamp = payload['timestamp']
log_line = str(timestamp) + "," + str(datetime.datetime.now().timestamp()) + "\n"
self.timelog_stream.write(log_line)
except Exception as e:
print(e)
def handle_exit(self, signum, frame):
# Disconnect the client
self.mqtt_client.disconnect()
# Close the files
self.rtcm3_op_stream.close()
self.timelog_stream.close()
# Specify that the mqtt client has safely terminated.
self.event_semaphore.release()
"""
Start the MQTT client and for it to exit
"""
def main(self):
# Start the mqtt client.
self.mqtt_client.loop_start()
print ("Saving the logs")
# Now wait for the mqtt client to safely terminate.
self.event_semaphore.acquire(blocking=True)
print ("Quitting")
return
if __name__ == "__main__":
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-s', '--scenario',
help="Scenario in which the client is running. This is used as a prefix for the file",
type=str)
parser.add_argument('-h','--hostname',
help="hostname of the MQTT broker",
type=str)
parser.add_argument('-p', '--port',
help="Scenario in which the client is running. This is used as a prefix for the file",
type=int)
args = parser.parse_args()
if None in [ args.scenario, args.hostname, args.port]:
parser.print_help()
else:
s = MQTTSubscriber(args.scenario, args.hostname, args.port)
s.main()
The folder contains the relay client
It has three files
1. The rtkrcv.conf used by rtkrcv. The configuration file specifies that rtkrcv publish the received information over a tcp port (specified in the conf file)
2. The python code to relay the received information to an mqtt broker
3. The requirements.txt used to create the python environment.
## RTKRCV Installation
Please place the rtkrcv binary in this folder. The steps for creating the binary are as follows.
- Download the source repository of rtklib at https://github.com/tomojitakasu/RTKLIB
+ This code has been tested with RTKLIB version 2.4.3 b33
+ https://github.com/tomojitakasu/RTKLIB/archive/v2.4.3-b33.tar.gz
- Extract the tar ball. This should create a folder named in RTKLIB-2.4.3-b33
- Perform the following steps to create the rtkrcv binary.
```
cd RTKLIB-2.4.3-b33/app
make
cd -
```
- Note that the above steps requires build-essential packages (if it is not previously installed). Also you will notice some warning during the compilation phase.
- Create a link to the binary in this directory. This is done to avoid specifying the path of the rtkrcv.conf
```
ln -s RTKLIB-2.4.3-b33/app/rtkrcv/gcc/rtkrcv .
```
## Mosquitto Broker Installation
Install the mosquitto broker and disable the mosquitto service if we want to run it on a specifi port.
```
apt install mosquitto
systemctl disable mosquitto
```
## Python environment for rtcm3\_relay
Create a python environment where paho-mqtt is installed. This code was tested using python 3.8
Create a venv folder in this directory.
```
python3.8 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
- You might see some errors about bdist\_wheel which can be ignored.
Now open three terminals (as persistent screen [https://www.gnu.org/software/screen/] ) on the server.
- On one screen start the
./rtkrcv
> start - use this command if you want to start the rtkrcv
> stop - for stopping the rtkrcv
> shutdown - for quitting
- On the second screen start mosquitto -p <portnumber>. We use 8883 because that port is open on our server for incoming connections
```
mosquitto -p 8883
```
- On the third screen run rtcm\_relay.py
```
#> python rtcm_relay.py -r localhost -p 11235 -h localhost -b localhost -m 8883
```
setuptools
paho-mqtt == 1.5.0
import paho.mqtt.client as mqtt
import json
import base64
import socket
import datetime
import signal
import argparse
RTCM3_PREAMBLE = b'\xd3'
# Specify the host name and port number of the broker here.
MQTTBROKER_HOSTNAME = "localhost"
MQTTBROKER_PORT = 8883
# The port number on which in the rtkrcv is publishing the RTCM3 messages.
RTKRCV_SRV_HOST = "localhost"
RTKRCV_SRV_PORT = 11235
# The topic for the messages.
MQTT_RTCM3_TOPIC = "rtcm3"
# The client ID used for publish
MQTT_RTCM3_RELAY_ID = "rtcm3relay"
class MQTTRelay:
mqtt_client = None
sock = None
"""
create an MQTT client that connects to the broker
"""
def __init__(self, mqtthost, mqttport):
self.mqtt_client = mqtt.Client(client_id=MQTT_RTCM3_RELAY_ID, clean_session=True, userdata=None, transport='tcp')
self.mqtt_client.on_connect = self._mqtt_connect
self.mqtt_client.on_disconnect = self._mqtt_disconnect
self.mqtt_client.connect(mqtthost, mqttport)
print("Connected to MQTT Broker")
self.sock = None
# Specify the signal handlers.
signal.signal(signal.SIGINT, self.handle_exit)
signal.signal(signal.SIGTERM, self.handle_exit)
return
"""
Debug messages to show when connected
"""
def _mqtt_connect(self, client, obj, flags, rc):
return
"""
Do a clean disconnect
"""
def _mqtt_disconnect(self, client, userdata, rc=0):
print ("Disconnecting from the MQTT broker")
client.loop_stop()
return
# """
# Publish a message with the given topic .. Made it inline.
# """
# def publish_rtcm3(self, rtcm3_frame):
# self.mqtt_client.publish(topic=MQTT_RTCM3_TOPIC,
# payload=json.dumps({'rtcm3':rtcm3_frame, 'timestamp': datetime.datetime.now().timestamp()}))
# return
def handle_exit(self, signum, frame):
# Disconnect the client
self.sock.close()
self.mqtt_client.disconnect()
return
# """
# Read the log file and publish each RTCM3 frame in an individual message.
# """
# def rtcm3_relay_file(fname, publisher):
# print("Reading File Now")
# cnt = 0
# with open(fname, mode="rb") as bfile:
# # skip the first few bytes which are newline characters.
# data = bfile.read(1)
# while data != RTCM3_PREAMBLE:
# data = bfile.read(1)
# rtcm3_frame = bytes()
# rtcm3_frame += base64.encodebytes(data)
# while data != b"":
# cnt = cnt + 1
# data = bfile.read(1)
# print(data)
# if data == RTCM3_PREAMBLE:
# print("Found preamble")
# utf8_rtcm3_frame = rtcm3_frame.decode('utf-8')
# publisher.publish_rtcm3(utf8_rtcm3_frame)
# rtcm3_frame = bytes()
# rtcm3_frame += base64.encodebytes(data)
# print(cnt)
# return True
"""
Connect to the tcp server created by rtknavi/rtklib.
Read the rtcm3 frames, and publish each frame as a message.
"""
def rtcm3_relay_socket(self, srv_host, srv_port):
buff_size = 4096
rtcm3_frame = bytes()
first_preamble = True
try:
self.sock = socket.create_connection((srv_host, srv_port))
print ("Connected to RTKRCV tcp port. Relaying the RTCM3 messages now")
while True:
data = self.sock.recv(4096)
data = [bytes(data[i:i+1]) for i in range(len(data))]
for i in range(len(data)):
data_byte = data[i]
# This needs to be optimized. Currently, we create a message each time the preamble is seen.
# The correct way would be to fetch the length, and encode the payload up to the length.
if data_byte == RTCM3_PREAMBLE:
if first_preamble is False:
self.mqtt_client.publish(topic=MQTT_RTCM3_TOPIC,
json.dumps({'rtcm3':base64.b64encode(rtcm3_frame).decode('utf-8'),
'timestamp': datetime.datetime.now().timestamp()}))
#utf8_rtcm3_frame = base64.b64encode(rtcm3_frame).decode('utf-8')
#self.publish_rtcm3(utf8_rtcm3_frame)
first_preamble = False
rtcm3_frame = bytes()
rtcm3_frame += data_byte
except IOError:
pass
except Exception as e:
print(e)
return True
def main(mqtthost, mqttport, rtkhost, rtkport):
mqtt_relay = MQTTRelay(mqtthost, mqttport)
mqtt_relay.rtcm3_relay_socket(rtkhost, rtkport)
print ("Quitting")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-r','--rtktcphost',
help="hostname where the rtrcv is exporting rtcm3 over tcp",
type=str)
parser.add_argument('-p', '--rtktcpport',
help="port number where the rtrcv is exporting rtcm3 over tcp",
type=int)
parser.add_argument('-b','--mqtthost',
help="hostname of the MQTT broker",
type=str)
parser.add_argument('-m', '--mqttport',
help="port number of the MQTT broker",
type=int)
args = parser.parse_args()
if None in [ args.rtktcphost, args.rtktcpport, args.mqtthost, args.mqttport ]:
parser.print_help()
else:
main(args.mqtthost, args.mqttport, args.rtktcphost, args.rtktcpport)
REPLACE THIS FILE WITH THE RTKRCV BINARY
# RTKNAVI options (2020/05/12 08:49:05, v.2.4.3 b33)
pos1-posmode =single # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed)
pos1-frequency =l1+l2 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l5)
pos1-soltype =forward # (0:forward,1:backward,2:combined)
pos1-elmask =15 # (deg)
pos1-snrmask_r =off # (0:off,1:on)
pos1-snrmask_b =off # (0:off,1:on)
pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0
pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0
pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0
pos1-dynamics =off # (0:off,1:on)
pos1-tidecorr =off # (0:off,1:on,2:otl)
pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec)
pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd)
pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
pos1-posopt1 =off # (0:off,1:on)
pos1-posopt2 =off # (0:off,1:on)
pos1-posopt3 =off # (0:off,1:on,2:precise)
pos1-posopt4 =off # (0:off,1:on)
pos1-posopt5 =off # (0:off,1:on)
pos1-posopt6 =off # (0:off,1:on)
pos1-exclsats = # (prn ...)
pos1-navsys =47 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp)
pos2-armode =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
pos2-gloarmode =off # (0:off,1:on,2:autocal)
pos2-bdsarmode =off # (0:off,1:on)
pos2-arthres =3
pos2-arthres1 =0.9999
pos2-arthres2 =0.25
pos2-arthres3 =0.1
pos2-arthres4 =0.05
pos2-arlockcnt =0
pos2-arelmask =0 # (deg)
pos2-arminfix =10
pos2-armaxiter =1
pos2-elmaskhold =0 # (deg)
pos2-aroutcnt =5
pos2-maxage =30 # (s)
pos2-syncsol =off # (0:off,1:on)
pos2-slipthres =0.05 # (m)
pos2-rejionno =30 # (m)
pos2-rejgdop =30
pos2-niter =1
pos2-baselen =0 # (m)
pos2-basesig =0 # (m)
out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea)
out-outhead =off # (0:off,1:on)
out-outopt =off # (0:off,1:on)
out-outvel =off # (0:off,1:on)
out-timesys =gpst # (0:gpst,1:utc,2:jst)
out-timeform =hms # (0:tow,1:hms)
out-timendec =3
out-degform =deg # (0:deg,1:dms)
out-fieldsep =
out-outsingle =off # (0:off,1:on)
out-maxsolstd =0 # (m)
out-height =ellipsoidal # (0:ellipsoidal,1:geodetic)
out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
out-solstatic =all # (0:all,1:single)
out-nmeaintv1 =0 # (s)
out-nmeaintv2 =0 # (s)
out-outstat =off # (0:off,1:state,2:residual)
stats-eratio1 =100
stats-eratio2 =100
stats-errphase =0.003 # (m)
stats-errphaseel =0.003 # (m)
stats-errphasebl =0 # (m/10km)
stats-errdoppler =1 # (Hz)
stats-stdbias =30 # (m)
stats-stdiono =0.03 # (m)
stats-stdtrop =0.3 # (m)
stats-prnaccelh =10 # (m/s^2)
stats-prnaccelv =10 # (m/s^2)
stats-prnbias =0.0001 # (m)
stats-prniono =0.001 # (m)
stats-prntrop =0.0001 # (m)
stats-prnpos =0 # (m)
stats-clkstab =5e-12 # (s/s)
ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant1-pos1 =90 # (deg|m)
ant1-pos2 =0 # (deg|m)
ant1-pos3 =-6335367.6285 # (m|m)
ant1-anttype =
ant1-antdele =0 # (m)
ant1-antdeln =0 # (m)
ant1-antdelu =0 # (m)
ant2-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant2-pos1 =90 # (deg|m)
ant2-pos2 =0 # (deg|m)
ant2-pos3 =-6335367.6285 # (m|m)
ant2-anttype =
ant2-antdele =0 # (m)
ant2-antdeln =0 # (m)
ant2-antdelu =0 # (m)
ant2-maxaveep =3600
ant2-initrst =on # (0:off,1:on)
misc-timeinterp =off # (0:off,1:on)
misc-sbasatsel =0 # (0:all)
misc-rnxopt1 =
misc-rnxopt2 =
misc-pppopt =
file-satantfile =
file-rcvantfile =
file-staposfile =
file-geoidfile =
file-ionofile =
file-dcbfile =
file-eopfile =
file-blqfile =
file-tempdir =/tmp/
file-geexefile =
file-solstatfile =
file-tracefile =
#
inpstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr2-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr1-path =
inpstr2-path =<username:password>@<hostname>:<mount>
inpstr3-path =
inpstr1-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr3-format =rtcm2 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3)
inpstr2-nmeareq =latlon # (0:off,1:latlon,2:single)
inpstr2-nmealat =<lat> # (deg)
inpstr2-nmealon =<long> # (deg)
outstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
outstr1-path =
outstr2-path =
outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea)
outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea)
logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr2-type =tcpsvr # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr1-path =
logstr2-path =:11235 # port number on which the data is exposed to the relay
logstr3-path =
misc-svrcycle =10 # (ms)
misc-timeout =10000 # (ms)
misc-reconnect =10000 # (ms)
misc-nmeacycle =5000 # (ms)
misc-buffsize =32768 # (bytes)
misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr)
misc-proxyaddr =
misc-fswapmargin =30 # (s)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment