Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
guiLogic.py
Go to the documentation of this file.
1from enum import Enum
2import mapFile
3import numpy as np
4class editorMode(Enum):
5 MOVE = 1
6 ADD = 2
7 REMOVE = 3
8 LANE_CONNECT_LEFT = 4
9 LANE_CONNECT_RIGHT = 5
10 TIMEKEEPING_START = 6
11 TIMEKEEPING_FINISH = 7
12 TIMEKEEPING_SECTOR = 8
13class landmarkType(Enum):
14 UNDEFINED = 0
15 BLUE = 1
16 YELLOW = 2
17 ORANGE = 3
18 BIG_ORANGE = 4
19 INVISIBLE = 5
20 TIMEKEEPING = 6
21
22class guiLogic():
23 def __init__(self, *args, **kwargs):
24 self.editorMode = editorMode.ADD
25 self.landmarkType = landmarkType.UNDEFINED
26 self.graphicsView = None
27 self.cones = []
28 self.coneColorMap = {}
32 self.startPosition = np.array([0,0,0])
33 self.startOrientation = np.array([0,0,0])
34 d2r = np.pi / 180.0
35 self.originGeodeticCoordinates = np.array([51.001745, 13.641794,210])
36 self.originENURotation = d2r * np.array([0,0,45])
37
38 # https://stackoverflow.com/questions/27161533/find-the-shortest-distance-between-a-point-and-line-segments-not-line
39 def lineseg_dists(self, p, a, b):
40 """Cartesian distance from point to line segment
41
42 Edited to support arguments as series, from:
43 https://stackoverflow.com/a/54442561/11208892
44
45 Args:
46 - p: np.array of single point, shape (2,) or 2D array, shape (x, 2)
47 - a: np.array of shape (x, 2)
48 - b: np.array of shape (x, 2)
49 """
50 # normalized tangent vectors
51 d_ba = b - a
52 d = np.divide(d_ba, (np.hypot(d_ba[:, 0], d_ba[:, 1])
53 .reshape(-1, 1)))
54
55 # signed parallel distance components
56 # rowwise dot products of 2D vectors
57 s = np.multiply(a - p, d).sum(axis=1)
58 t = np.multiply(p - b, d).sum(axis=1)
59
60 # clamped parallel distance
61 h = np.maximum.reduce([s, t, np.zeros(len(s))])
62
63 # perpendicular distance component
64 # rowwise cross products of 2D vectors
65 d_pa = p - a
66 c = d_pa[:, 0] * d[:, 1] - d_pa[:, 1] * d[:, 0]
67
68 return np.hypot(h, c)
69
70 def getClosestInd(self, point, list):
71 bestInd = 0
72 bestDist = 999
73 for i in range(len(list)):
74 dist = np.linalg.norm(list[i][0]-point)
75 if(dist < bestDist):
76 bestDist = dist
77 bestInd = i
78 return bestInd
79
81 if(len(self.lanesConnectionLeft) == 0 or len(self.lanesConnectionRight) == 0):
82 return 0
83 minDistance = 999
84 offsetLane = 0
85 toBeckCheckedConesLeft = self.lanesConnectionLeft[:-1]
86 toBeckCheckedConesRight = self.lanesConnectionRight[:-1]
87 for i in range(-offsetLane,len(toBeckCheckedConesLeft)-1):
88 p1 = toBeckCheckedConesLeft[i-2][0]
89 p2 = toBeckCheckedConesLeft[i-1][0]
90 p3 = toBeckCheckedConesLeft[i][0]
91 tangential = p3-p1
92 tangential = (1/np.linalg.norm(tangential)) * tangential
93 projectionDistance = 4
94 normal = np.array([-tangential[1], tangential[0], 0])
95 normal = projectionDistance * normal
96 closestInd = self.getClosestInd(p2 + normal, toBeckCheckedConesRight)
97 indicesToCheck = np.linspace(closestInd-5, closestInd+5, num = 11, dtype=int)
98 a = []
99 b = []
100 for j in indicesToCheck:
101 a.append(toBeckCheckedConesRight[j % len(toBeckCheckedConesRight)][0][0:2])
102 b.append(toBeckCheckedConesRight[(j+1) % len(toBeckCheckedConesRight)][0][0:2])
103 minDistance = min(minDistance, min(self.lineseg_dists(p2[0:2], np.array(a), np.array(b))))
104 return minDistance
105
106 def getTrackLength(self):
107 if(len(self.lanesConnectionLeft) == 0 or len(self.lanesConnectionRight) == 0):
108 return 0
109 leftLength = 0
110 rightLength = 0
111 offsetLane = 0
112 for i in range(-offsetLane,len(self.lanesConnectionLeft)):
113 p1 = self.lanesConnectionLeft[i-1][0]
114 p2 = self.lanesConnectionLeft[i][0]
115 dist = np.linalg.norm(p1-p2)
116 leftLength += dist
117 for i in range(-offsetLane,len(self.lanesConnectionRight)):
118 p1 = self.lanesConnectionRight[i-1][0]
119 p2 = self.lanesConnectionRight[i][0]
120 dist = np.linalg.norm(p1-p2)
121 rightLength += dist
122 return 0.5*(leftLength + rightLength)
123
125 if(len(self.lanesConnectionLeft) == 0 or len(self.lanesConnectionRight) == 0):
126 return 0
127 maxDist = 0
128 offsetLane = -1
129 for i in range(-offsetLane,len(self.lanesConnectionLeft)):
130 p1 = self.lanesConnectionLeft[i-1][0]
131 p2 = self.lanesConnectionLeft[i][0]
132 dist = np.linalg.norm(p1-p2)
133 maxDist = max(maxDist, dist)
134 for i in range(-offsetLane,len(self.lanesConnectionRight)):
135 p1 = self.lanesConnectionRight[i-1][0]
136 p2 = self.lanesConnectionRight[i][0]
137 dist = np.linalg.norm(p1-p2)
138 maxDist = max(maxDist, dist)
139 return maxDist
140
141 # https://stackoverflow.com/questions/41144224/calculate-curvature-for-3-points-x-y
142 def getCurvature(self, point1, point2, point3):
143 # Calculating length of all three sides
144 len_side_1 = round( np.linalg.norm(point1-point2), 2)
145 len_side_2 = round( np.linalg.norm(point2-point3), 2)
146 len_side_3 = round( np.linalg.norm(point1-point3), 2)
147
148 # sp is semi-perimeter
149 sp = (len_side_1 + len_side_2 + len_side_3) / 2
150
151 # Calculating area using Herons formula
152 area = np.sqrt(max(sp * (sp - len_side_1) * (sp - len_side_2) * (sp - len_side_3),0.00001))
153
154 # Calculating curvature using Menger curvature formula
155 curvature = (4 * area) / max(len_side_1 * len_side_2 * len_side_3,0.0000001)
156
157 return curvature
158
160 if(len(self.lanesConnectionLeft) == 0 or len(self.lanesConnectionRight) == 0):
161 return 0
162 minRadius = 999
163 offsetLane = 0
164 toBeckCheckedConesLeft = self.lanesConnectionLeft[:-1]
165 toBeckCheckedConesRight = self.lanesConnectionRight[:-1]
166 for i in range(-offsetLane,len(toBeckCheckedConesLeft)-2):
167 p1 = toBeckCheckedConesLeft[i-2][0]
168 p2 = toBeckCheckedConesLeft[i-1][0]
169 p3 = toBeckCheckedConesLeft[i][0]
170 tangential = p3-p1
171 tangential = (1/np.linalg.norm(tangential)) * tangential
172 projectionDistance = 4
173 normal = np.array([-tangential[1], tangential[0], 0])
174 normal = projectionDistance * normal
175 closestInd = self.getClosestInd(p2 + normal, self.lanesConnectionRight)
176 p4 = toBeckCheckedConesLeft[(closestInd-1) % len(toBeckCheckedConesLeft)][0]
177 p5 = toBeckCheckedConesLeft[(closestInd) % len(toBeckCheckedConesLeft)][0]
178 p6 = toBeckCheckedConesLeft[(closestInd+1) % len(toBeckCheckedConesLeft)][0]
179 minRadius = min(minRadius, max(1/self.getCurvature(p1[0:2],p2[0:2],p3[0:2]), 1/self.getCurvature(p4[0:2],p5[0:2],p6[0:2])))
180 return minRadius
181
182 def readMapFile(self, path):
183 self.cones = []
184 self.coneColorMap = {}
185 self.lanesConnectionLeft = []
186 self.lanesConnectionRight = []
187 self.timeKeepingGates = []
188 conesUnknown, left, right, tk, connected, start, earthToTrack = mapFile.readYaml(path)
189 self.startPosition = start[0]
190 self.startOrientation = start[1]
191 self.originGeodeticCoordinates = earthToTrack[0]
192 self.originENURotation = earthToTrack[1]
193 for i in conesUnknown:
194 self.cones.append([i[0], mapFile.stringToLandmarkType(i[1])])
195 for i in left:
196 l = [i[0], mapFile.stringToLandmarkType(i[1])]
197 self.cones.append(l)
198 self.lanesConnectionLeft.append(l)
199 for i in right:
200 l = [i[0], mapFile.stringToLandmarkType(i[1])]
201 self.cones.append(l)
202 self.lanesConnectionRight.append(l)
203 duringLine = False
204 for i in tk:
205 l = [i[0], mapFile.stringToLandmarkType(i[1])]
206 self.cones.append(l)
207 if(duringLine):
208 self.timeKeepingGates[-1].append(l)
209 duringLine = False
210 else:
211 self.timeKeepingGates.append([l])
212 duringLine = True
213 if(len(self.lanesConnectionLeft) >= 2 and connected):
214 self.lanesConnectionLeft.append(self.lanesConnectionLeft[0])
215 if(len(self.lanesConnectionRight) >= 2 and connected):
216 self.lanesConnectionRight.append(self.lanesConnectionRight[0])
217
218 def drawCones(self):
219 self.graphicsView.initFromLoad()
220 # for c in self.cones:
221 # self.graphicsView.addCone(c)
222 def writeMapFile(self, path):
223 conesUnknown = []
224 for i in self.cones:
225 good = True
226 for j in self.lanesConnectionLeft:
227 good = good and (i is not j)
228 for j in self.lanesConnectionRight:
229 good = good and (i is not j)
230 good = good and (i[1] != landmarkType.TIMEKEEPING)
231 if(good):
232 conesUnknown.append(i)
233 timeKeeping = []
234 for i in self.timeKeepingGates:
235 timeKeeping.append(i[0])
236 timeKeeping.append(i[1])
237 mapFile.writeYaml(path, conesUnknown, self.lanesConnectionLeft[:-1], self.lanesConnectionRight[:-1], timeKeeping, [self.startPosition, self.startOrientation], [self.originGeodeticCoordinates, self.originENURotation])
readMapFile(self, path)
Definition guiLogic.py:182
lineseg_dists(self, p, a, b)
Definition guiLogic.py:39
getMaxLaneDistance(self)
Definition guiLogic.py:124
getClosestInd(self, point, list)
Definition guiLogic.py:70
__init__(self, *args, **kwargs)
Definition guiLogic.py:23
writeMapFile(self, path)
Definition guiLogic.py:222
getMinOuterRadius(self)
Definition guiLogic.py:159
getMinTrackWidth(self)
Definition guiLogic.py:80
getCurvature(self, point1, point2, point3)
Definition guiLogic.py:142
stringToLandmarkType(string)
Definition mapFile.py:21
writeYaml(fileName, cones, leftLane, rightLane, timeKeeping, startPose, earthToTrack)
Definition mapFile.py:52
readYaml(fileName)
Definition mapFile.py:96
double round(double number, int n)
round to n decimal places
Definition tests.cpp:17