|
1 | | -import sys |
2 | 1 | import serial |
3 | 2 | import math |
4 | 3 | import operator |
5 | 4 | import time |
6 | 5 | import socket |
| 6 | +import os.path |
| 7 | +import os |
7 | 8 |
|
8 | | -DST_IP = "127.0.0.4" |
| 9 | +DST_IP = "127.0.0.3" |
9 | 10 | DST_PORT = 5005 |
10 | 11 |
|
| 12 | +MON_IP = "127.0.0.6" |
| 13 | +MON_PORT = 5005 |
| 14 | + |
| 15 | +mon = 0 |
| 16 | +log = time.time() |
| 17 | + |
| 18 | +# initialize for VDR |
| 19 | +five = 0 |
| 20 | +setx_total = 0 |
| 21 | +setx_run = [0] * 5 |
| 22 | +sety_total = 0 |
| 23 | +sety_run = [0] * 5 |
| 24 | +drift_total = 0 |
| 25 | +drift_run = [0] * 5 |
| 26 | + |
| 27 | +# initialize for VLW |
11 | 28 | vlwfirst = 1 |
12 | 29 | vlwinit = 0.0 |
13 | | -t_dpt = 0 |
14 | | -t_print = time.time() |
15 | | -t_fail = 0.0 |
16 | | - |
17 | | -sddpt = '' |
18 | | -mtw = '' |
19 | | -yxmtw = '' |
20 | | -vwvhw = '' |
21 | | -vlw = '' |
22 | | -vwvlw = '' |
23 | 30 |
|
24 | | -ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=1) |
| 31 | +# determine dst port |
| 32 | +f = open('gps_port', 'r') |
| 33 | +gps_port = f.readline() |
| 34 | +f.close() |
| 35 | +dst_port = "1" |
| 36 | +if gps_port == "1": |
| 37 | + dst_port = "0" |
| 38 | +ser = serial.Serial('/dev/ttyUSB' + dst_port, 4800, timeout=5) |
25 | 39 |
|
26 | 40 | while True: |
| 41 | + |
| 42 | + # health monitor |
27 | 43 | hack = time.time() |
| 44 | + if hack - mon > .5: |
| 45 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| 46 | + sock.sendto(str(hack), (MON_IP, MON_PORT)) |
| 47 | + mon = hack |
28 | 48 |
|
| 49 | + # log raw input |
29 | 50 | dst_raw = ser.readline() |
30 | | - |
| 51 | + f = open('dstraw', 'a') |
| 52 | + f.write(dst_raw) |
| 53 | + f.close() |
| 54 | + if hack - log > 60: |
| 55 | + os.remove('dstraw') |
| 56 | + f = open('dstraw', 'w') |
| 57 | + f.write("Serial port " + dst_port + ": " + time.asctime( time.localtime(time.time()) ) + "\r\n") |
| 58 | + f.close() |
| 59 | + log = hack |
| 60 | + |
| 61 | + # checking to see if it's a valid NMEA sentence |
31 | 62 | if "*" in dst_raw: |
32 | 63 | dst_split = dst_raw.split('*') |
33 | 64 | dst_sentence = dst_split[0].strip('$') |
|
36 | 67 | if len(cs) == 1: |
37 | 68 | cs = "0" + cs |
38 | 69 |
|
| 70 | + # if it is a valid NMEA sentence |
39 | 71 | if cs0 == cs: |
40 | | - |
41 | | - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
42 | 72 | dst_vars = dst_sentence.split(',') |
43 | 73 | title = dst_vars[0] |
44 | 74 |
|
| 75 | + # depth sentence |
45 | 76 | if title == "SDDPT": |
46 | | - sddpt = dst_raw[:-2] |
| 77 | + |
| 78 | + # roll and pitch from imu |
| 79 | + try: |
| 80 | + f = open('imu_bus', 'r') |
| 81 | + line = f.readline() |
| 82 | + f.close() |
| 83 | + imu_split = line.split(',') |
| 84 | + imu_hack = float(imu_split[0]) |
| 85 | + roll = float(imu_split[2]) |
| 86 | + pitch = float(imu_split[3]) |
| 87 | + |
| 88 | + except ValueError: |
| 89 | + time.sleep(.03) |
| 90 | + f = open('imu_bus', 'r') |
| 91 | + line = f.readline() |
| 92 | + f.close() |
| 93 | + imu_split = line.split(',') |
| 94 | + imu_hack = float(imu_split[0]) |
| 95 | + roll = float(imu_split[2]) |
| 96 | + pitch = float(imu_split[3]) |
| 97 | + |
| 98 | + # correct depth for 23 degree offset from centerline, but if roll/pitch |
| 99 | + # are from the last 3 seconds, correct depth for attitude |
| 100 | + depth = round(float(dst_vars[1])*math.cos(math.radians(23)),1) |
| 101 | + if time.time() - imu_hack < 3.0: |
| 102 | + depth = round(float(dst_vars[1])*math.cos(math.radians(23-roll))*math.cos(math.radians(pitch)),1) |
| 103 | + |
| 104 | + # assemble the sentence with .5 meter offset from waterline |
| 105 | + dpt = "SDDPT," + str(depth) + ",0.50" |
| 106 | + dptcs = format(reduce(operator.xor,map(ord,dpt),0),'X') |
| 107 | + if len(dptcs) == 1: |
| 108 | + dptcs = "0" + dptcs |
| 109 | + sddpt = "$" + dpt + "*" + dptcs + "\r\n" |
| 110 | + |
| 111 | + # to kplex |
| 112 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
47 | 113 | sock.sendto(sddpt, (DST_IP, DST_PORT)) |
48 | | - t_dpt = hack |
49 | | - t_fail = 0.0 |
50 | 114 |
|
| 115 | + # mean water temp sentence |
51 | 116 | if title == "YXMTW": |
52 | | - mtw = dst_vars[0] + "," + str(float(dst_vars[1]) * 9 / 5 + 32) + ",F" |
| 117 | + |
| 118 | + # convert to fahrenheit |
| 119 | + mtw = dst_vars[0] + "," + str(int(float(dst_vars[1]) * 9 / 5 + 32)) + ",F" |
53 | 120 | cs = format(reduce(operator.xor,map(ord,mtw),0),'X') |
54 | 121 | if len(cs) == 1: |
55 | 122 | cs = "0" + cs |
56 | | - yxmtw = "$" + mtw + "*" + cs |
| 123 | + yxmtw = "$" + mtw + "*" + cs + "\r\n" |
| 124 | + |
| 125 | + # to kplex |
| 126 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
57 | 127 | sock.sendto(yxmtw, (DST_IP, DST_PORT)) |
58 | 128 |
|
| 129 | + # vessel waterspeed sentence and current set and drift |
59 | 130 | if title == "VWVHW": |
60 | | - vwvhw = dst_raw[:-2] |
| 131 | + |
| 132 | + # heading and roll from imu |
| 133 | + try: |
| 134 | + f = open('imu_bus', 'r') |
| 135 | + line = f.readline() |
| 136 | + f.close() |
| 137 | + imu_split = line.split(',') |
| 138 | + imu_hack = float(imu_split[0]) |
| 139 | + heading = float(imu_split[1]) |
| 140 | + roll = float(imu_split[2]) |
| 141 | + except ValueError: |
| 142 | + f.close() |
| 143 | + time.sleep(.03) |
| 144 | + f = open('imu_bus', 'r') |
| 145 | + line = f.readline() |
| 146 | + f.close() |
| 147 | + imu_split = line.split(',') |
| 148 | + imu_hack = float(imu_split[0]) |
| 149 | + heading = float(imu_split[1]) |
| 150 | + roll = float(imu_split[2]) |
| 151 | + |
| 152 | + # course and groundspeed from gps |
| 153 | + try: |
| 154 | + f = open('gps_bus', 'r') |
| 155 | + line = f.readline() |
| 156 | + gps_split = line.split(',') |
| 157 | + f.close() |
| 158 | + gps_hack = float(gps_split[0]) |
| 159 | + valid = gps_split[1] |
| 160 | + course = float(gps_split[2]) |
| 161 | + groundspeed = float(gps_split[3]) |
| 162 | + except ValueError: |
| 163 | + time.sleep(.03) |
| 164 | + f = open('gps_bus', 'r') |
| 165 | + line = f.readline() |
| 166 | + f.close() |
| 167 | + gps_split = line.split(',') |
| 168 | + gps_hack = float(gps_split[0]) |
| 169 | + valid = gps_split[1] |
| 170 | + course = float(gps_split[2]) |
| 171 | + groundspeed = float(gps_split[3]) |
| 172 | + |
| 173 | + # calculate corrected waterspeed from heel and velocity |
| 174 | + waterspeed = float(dst_vars[5]) |
| 175 | + sensor_angle = 23.0 |
| 176 | + if time.time() - imu_hack < 3.0: |
| 177 | + sensor_angle = math.fabs(23.0-roll) |
| 178 | + five_knot_correction = -.02 * sensor_angle |
| 179 | + ten_knot_correction = sensor_angle * (.035 - .0065 * sensor_angle) - 2 |
| 180 | + if sensor_angle > 10.0: |
| 181 | + ten_knot_correction = -.03 * sensor_angle - 2 |
| 182 | + if waterspeed < 5.0: |
| 183 | + waterspeed = round(waterspeed + (five_knot_correction * waterspeed / 5), 1) |
| 184 | + else: |
| 185 | + waterspeed = round((waterspeed + (waterspeed * (ten_knot_correction * (waterspeed - 5) - 2 * five_knot_correction * (waterspeed - 10))) / 50),1) |
| 186 | + |
| 187 | + # assemble the sentence |
| 188 | + vhw = "VWVHW," |
| 189 | + if time.time() - imu_hack < 3.0: |
| 190 | + vhw = vhw + str(int(heading)) |
| 191 | + else: vhw = vhw + '' |
| 192 | + vhw = vhw + ",T,,M," + str(waterspeed) + ",N,,K" |
| 193 | + vhwcs = format(reduce(operator.xor,map(ord,vhw),0),'X') |
| 194 | + if len(vhwcs) == 1: |
| 195 | + vhwcs = "0" + vhwcs |
| 196 | + vwvhw = "$" + vhw + "*" + vhwcs + "\r\n" |
| 197 | + |
| 198 | + # to kplex |
| 199 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
61 | 200 | sock.sendto(vwvhw, (DST_IP, DST_PORT)) |
62 | 201 |
|
| 202 | + # VDR set and drift |
| 203 | + if time.time() - imu_hack < 3.0 and time.time() - gps_hack < 3.0 and valid == "A": |
| 204 | + |
| 205 | + heading_radians = math.radians(heading) |
| 206 | + course_radians = math.radians(course) |
| 207 | + set0 = course_radians - heading_radians |
| 208 | + if set0 < 0: |
| 209 | + set0 = set0 + 2 * math.pi |
| 210 | + set_relative = math.pi - math.atan2(groundspeed * math.sin(set0), waterspeed - groundspeed * math.cos(set0)) |
| 211 | + if waterspeed == 0 and groundspeed == 0: |
| 212 | + set_relative = set0 |
| 213 | + set_radians = heading_radians + set_relative |
| 214 | + if set_radians > (2 * math.pi): |
| 215 | + set_radians = set_radians - (2 * math.pi) |
| 216 | + drift = math.sqrt(pow(waterspeed,2) + pow(groundspeed,2) - 2 * waterspeed * groundspeed * math.cos(set0)) |
| 217 | + |
| 218 | + # dampen out set and drift over the last five readings |
| 219 | + setx_total = setx_total - setx_run[five] |
| 220 | + setx_run[five] = math.cos(set_radians) |
| 221 | + setx_total = setx_total + setx_run[five] |
| 222 | + setx_ave = setx_total / 5 |
| 223 | + sety_total = sety_total - sety_run[five] |
| 224 | + sety_run[five] = math.sin(set_radians) |
| 225 | + sety_total = sety_total + sety_run[five] |
| 226 | + sety_ave = sety_total / 5 |
| 227 | + set_radians = math.atan2(sety_ave, setx_ave) |
| 228 | + if set_radians < 0: |
| 229 | + set_radians = set_radians + 2 * math.pi |
| 230 | + set_true = math.degrees(set_radians) |
| 231 | + set_apparent = set_true - heading |
| 232 | + if set_apparent < 0: |
| 233 | + set_apparent = set_apparent + 360 |
| 234 | + |
| 235 | + drift_total = drift_total - drift_run[five] |
| 236 | + drift_run[five] = drift |
| 237 | + drift_total = drift_total + drift_run[five] |
| 238 | + drift = drift_total / 5 |
| 239 | + five = five + 1 |
| 240 | + if five > 4: |
| 241 | + five = 0 |
| 242 | + |
| 243 | + # assemble the sentence |
| 244 | + vdr = "IIVDR,A," + str(int(set_true)) + ",T,,,M," + str(round(drift,1)) + ",N" |
| 245 | + vdrcs = format(reduce(operator.xor,map(ord,vdr),0),'X') |
| 246 | + if len(vdrcs) == 1: |
| 247 | + vdrcs = "0" + vdrcs |
| 248 | + iivdr = "$" + vdr + "*" + vdrcs + "\r\n" |
| 249 | + |
| 250 | + # ghost MWV sentence to show set/drift instead of wind |
| 251 | + mwv = "IIMWV," + str(int(set_apparent)) + ",R," + str(round(drift,1)) + ",N,A" |
| 252 | + mwvcs = format(reduce(operator.xor,map(ord,mwv),0),'X') |
| 253 | + if len(mwvcs) == 1: |
| 254 | + mwvcs = "0" + mwvcs |
| 255 | + iimwv = "$" + mwv + "*" + mwvcs + "\r\n" |
| 256 | + |
| 257 | + # to kplex |
| 258 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| 259 | + sock.sendto(iivdr + iimwv, (DST_IP, DST_PORT)) |
| 260 | + |
| 261 | + # voyage log sentence |
63 | 262 | if title == "VWVLW": |
| 263 | + |
| 264 | + # calculate present trip total vs overall total |
64 | 265 | if vlwfirst == 1: |
65 | 266 | vlwinit = dst_vars[1] |
66 | 267 | vlwfirst = 0 |
67 | 268 | trip = float(dst_vars[1]) - float(vlwinit) |
68 | 269 | vlw = "VWVLW," + dst_vars[1] + ",N," + str(trip) + ",N" |
69 | | - cs = format(reduce(operator.xor,map(ord,mtw),0),'X') |
| 270 | + cs = format(reduce(operator.xor,map(ord,vlw),0),'X') |
70 | 271 | if len(cs) == 1: |
71 | 272 | cs = "0" + cs |
72 | | - vwvlw = "$" + vlw + "*" + cs |
73 | | - sock.sendto(vwvlw, (DST_IP, DST_PORT)) |
| 273 | + vwvlw = "$" + vlw + "*" + cs + "\r\n" |
74 | 274 |
|
75 | | - if (hack - t_dpt) > 10.0: |
76 | | - if (hack - t_print > 1.0): |
77 | | - t_fail += 1.0 |
78 | | - dst_sentence = "IIXDR,DST_FAIL," + str(round(t_fail / 60, 1)) |
79 | | - cs = format(reduce(operator.xor,map(ord,dst_sentence),0),'X') |
80 | | - if len(cs) == 1: |
81 | | - cs = "0" + cs |
82 | | - dst_sentence = "$" + dst_sentence + "*" + cs |
83 | | - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
84 | | - sock.sendto(dst_sentence, (DST_IP, DST_PORT)) |
85 | | - t_print = hack |
| 275 | + # to kplex |
| 276 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| 277 | + sock.sendto(vwvlw, (DST_IP, DST_PORT)) |
0 commit comments