Skip to content

Commit 6ca6b74

Browse files
author
Gerd Gruenert
committed
Allow right turns
1 parent a1e02a0 commit 6ca6b74

File tree

3 files changed

+72
-29
lines changed

3 files changed

+72
-29
lines changed

traject/plot.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828
tparam = TurnParams(1.0, 1.0)
29-
turn = Turn(tparam, math.pi*1.0, 1)
29+
turn = Turn(tparam, math.pi*1.0)
3030

3131
# plot outer circle:
3232
omega = tparam.omega
@@ -43,16 +43,16 @@
4343

4444
# plot arc segment
4545
X = np.linspace(0, tparam.len_clothoid_part, 128, endpoint=True)
46-
tra = turn.state_clothoid_first(X)
46+
tra = turn._state_clothoid_first(X)
4747
ax0.plot(tra.x, tra.y, color="red", linewidth=1.0, linestyle="-")
4848

4949
# plot circle arc segment:
5050
X2 = np.linspace(tparam.len_clothoid_part, tparam.len_clothoid_part+turn.len_of_circular_part, 128, endpoint=True)
51-
tra = turn.state_circular(X2)
51+
tra = turn._state_circular(X2)
5252
ax0.plot(tra.x, tra.y, color="cyan", linewidth=2.0, linestyle="-")
5353

5454
# plot qi point:
55-
ax0.plot(tparam.state_qi.x, tparam.state_qi.y, "go")
55+
ax0.plot(turn.state_qi.x, turn.state_qi.y, "go")
5656

5757
# plot qj point:
5858
ax0.plot(turn.state_qj.x, turn.state_qj.y, "ro")
@@ -62,7 +62,7 @@
6262

6363
# plot second clothoid:
6464
X3 = np.linspace(tparam.len_clothoid_part+turn.len_of_circular_part, 2*tparam.len_clothoid_part+turn.len_of_circular_part, 128, endpoint=True)
65-
tra = turn.state_clothoid_second(X3)
65+
tra = turn._state_clothoid_second(X3)
6666
ax0.plot(tra.x, tra.y, color="red", linewidth=1.0, linestyle="-")
6767

6868
# Set x limits, ticks, etc.

traject/scc/turn.py

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,25 @@
1616
class Turn(object):
1717
"""This generates a turn that is always starting from angle 0, turning to an angle _delta"""
1818

19-
def __init__(self, _params, _delta, _dir):
19+
def __init__(self, _params, _delta):
2020
"""
2121
Parameters
2222
----------
2323
_params : TurnParams
2424
_delta : float
25-
Deflection of th Turn
25+
Deflection of th Turn; positive = left turn, negative = right turn
2626
_dir : int
2727
1 for left turn, -1 for right turn
2828
"""
2929

3030
self.params = _params
31-
self.delta = _delta
32-
self.dir = _dir
31+
self.delta = math.fabs(_delta)
32+
self.dir = 1
33+
if _delta < 0:
34+
self.dir = -1
3335

34-
assert(_delta > _params.delta_min)
35-
assert (_delta < 2 * math.pi)
36+
assert(self.delta > _params.delta_min)
37+
assert (self.delta < 2 * math.pi)
3638

3739
def state(self, s):
3840
"""
@@ -62,27 +64,27 @@ def state(self, s):
6264
theta = np.empty(len(s))
6365
kappa = np.empty(len(s))
6466

65-
first_clotho = self.state_clothoid_first(s[first_clotho_cond])
67+
first_clotho = self._state_clothoid_first(s[first_clotho_cond])
6668
x[first_clotho_cond] = first_clotho.x
6769
y[first_clotho_cond] = first_clotho.y
6870
theta[first_clotho_cond] = first_clotho.theta
6971
kappa[first_clotho_cond] = first_clotho.kappa
7072

71-
circ_seg = self.state_circular(s[circ_seg_cond])
73+
circ_seg = self._state_circular(s[circ_seg_cond])
7274
x[circ_seg_cond] = circ_seg.x
7375
y[circ_seg_cond] = circ_seg.y
7476
theta[circ_seg_cond] = circ_seg.theta
7577
kappa[circ_seg_cond] = circ_seg.kappa
7678

77-
second_clotho = self.state_clothoid_second(s[second_clotho_cond])
79+
second_clotho = self._state_clothoid_second(s[second_clotho_cond])
7880
x[second_clotho_cond] = second_clotho.x
7981
y[second_clotho_cond] = second_clotho.y
8082
theta[second_clotho_cond] = second_clotho.theta
8183
kappa[second_clotho_cond] = second_clotho.kappa
8284

83-
return State(x, y, theta, kappa)
85+
return State(x, self.dir * y, self.dir * theta, self.dir * kappa)
8486

85-
def state_circular(self, s):
87+
def _state_circular(self, s):
8688
# TODO: Fix the two-clothoids-only case:
8789
assert (self.delta > self.params.delta_min)
8890

@@ -98,8 +100,9 @@ def state_circular(self, s):
98100

99101
return State(x, y, angles, kappa)
100102

101-
def state_clothoid_first(self, s):
102-
"""
103+
def _state_clothoid_first(self, s):
104+
""" left turn, first clothoid segment
105+
103106
Parameters
104107
----------
105108
s : np.array
@@ -121,7 +124,7 @@ def state_clothoid_first(self, s):
121124

122125
return State(scale*ssa_csa[1], scale*ssa_csa[0], theta, kappa)
123126

124-
def state_clothoid_second(self, s):
127+
def _state_clothoid_second(self, s):
125128
"""
126129
Parameters
127130
----------
@@ -145,10 +148,9 @@ def state_clothoid_second(self, s):
145148
kappa = inv_clothoid_s / self.params.len_clothoid_part * self.params.kappa_max
146149

147150
state = State(-scale * ssa_csa[1], scale * ssa_csa[0], theta, kappa)
148-
state = state.rotate_then_translate(self.delta, self.state_qg.x, self.state_qg.y)
151+
state = state.rotate_then_translate(self.delta, self._state_qg.x, self._state_qg.y)
149152
return state
150153

151-
152154
@cached_property
153155
def len(self):
154156
return self.len_of_circular_part + 2*self.params.len_clothoid_part
@@ -165,8 +167,17 @@ def len_of_circular_part(self):
165167
return 2 * math.pi * self.params.inner_rad * angular_fraction
166168

167169
@cached_property
168-
def state_qj(self):
169-
"""Where the inner circle segment intersects the second clothoid"""
170+
def state_qi(self):
171+
"""Where the first clothoid intersects the inner circle (l/r-turn)"""
172+
st = self.params.state_qi
173+
st.y *= self.dir
174+
st.theta *= self.dir
175+
st.kappa *= self.dir
176+
return st
177+
178+
@cached_property
179+
def _state_qj(self):
180+
"""Where the inner circle segment intersects the second clothoid (left-turn)"""
170181

171182
ang = self.delta - self.params.delta_min/2
172183
x = self.params.omega[0] + self.params.inner_rad * np.sin(ang)
@@ -175,11 +186,30 @@ def state_qj(self):
175186

176187
return State(x, y, ang, kappa)
177188

189+
@cached_property
190+
def state_qj(self):
191+
"""Where the inner circle segment intersects the second clothoid (l/r-turn)"""
192+
st = self._state_qj
193+
st.y *= self.dir
194+
st.theta *= self.dir
195+
st.kappa *= self.dir
196+
return st
197+
178198
@cached_property
179199
def state_qg(self):
180-
"""The end of the second clothoid"""
200+
"""The end of the second clothoid (turn left | right for dir=1 | -1)"""
201+
st = self._state_qg
202+
st.y *= self.dir
203+
st.theta *= self.dir
204+
st.kappa *= self.dir
205+
return st
206+
207+
@cached_property
208+
def _state_qg(self):
209+
"""The end of the second clothoid (left-turn)"""
181210

182211
st = State(-self.params.omega[0], -self.params.omega[1], self.delta, 0)
183-
st = st.rotate_then_translate(self.delta+2*self.params.gamma, self.params.omega[0], self.params.omega[1])
212+
st = st.rotate_then_translate(self.delta + 2 * self.params.gamma, self.params.omega[0], self.params.omega[1])
184213

185214
return st
215+

traject/scc/turnparams.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,26 @@ def inner_rad(self):
3333

3434
@cached_property
3535
def outer_rad(self):
36-
return math.sqrt(self.omega[0]*self.omega[0] + self.omega[1]*self.omega[1])
36+
return math.sqrt(self.omega[0] * self.omega[0] + self.omega[1] * self.omega[1])
3737

3838
@cached_property
3939
def omega(self):
40-
"""The position of the center of the outer/inner circle."""
40+
"""The position of the center of the outer/inner circle. (left-turn)"""
4141
x_qi = self.state_qi.x
4242
y_qi = self.state_qi.y
4343
xo = x_qi - math.sin(self.state_qi.theta) / self.kappa_max
4444
yo = y_qi + math.cos(self.state_qi.theta) / self.kappa_max
4545
return xo, yo
4646

47+
@cached_property
48+
def omega_r(self):
49+
"""The position of the center of the outer/inner circle of a right-turn."""
50+
xo, yo = self.omega
51+
return xo, -yo
52+
4753
@cached_property
4854
def state_qi(self):
49-
"""Where the first clothoid intersects the inner circle"""
55+
"""Where the first clothoid intersects the inner circle (left-turn)"""
5056
scale = math.sqrt(math.pi / self.sigma_max)
5157

5258
ssa_csa = scipy.special.fresnel(math.sqrt(self.delta_min/math.pi))
@@ -61,8 +67,15 @@ def state_qi(self):
6167
)
6268
return st
6369

70+
@cached_property
71+
def state_qi_r(self):
72+
"""Where the first clothoid intersects the inner circle in a right-turn"""
73+
s = self.state_qi
74+
s.y *= -1
75+
return s
76+
6477
@cached_property
6578
def gamma(self):
6679
"""The angle between the outer circle tangent and the start/end vector."""
67-
gamma = math.atan(self.omega[0]/self.omega[1])
80+
gamma = math.atan(self.omega[0] / self.omega[1])
6881
return gamma

0 commit comments

Comments
 (0)