-
Notifications
You must be signed in to change notification settings - Fork 42
/
vehicle_control.py
143 lines (114 loc) · 4.47 KB
/
vehicle_control.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
'''
Vehicle Overtaking
Adjust cost and initial state to get desired behaviors
'''
import sympy as sp
import numpy as np
from ilqr import *
def vehicle_kinematics(state, action):
px, py, heading, vel, steer = state
accel, steer_vel = action
state_dot = sp.Matrix([
vel*sp.cos(heading),
vel*sp.sin(heading),
vel*sp.tan(steer),
accel,
steer_vel])
return state_dot
#state and action dimensions
n_x = 10
n_u = 2
#get symbolic variables
state, action = GetSyms(n_x, n_u)
#Construct dynamics
state_dot = sp.Matrix([0.0]*n_x)
# ego vehicle kinematics
state_dot[:5, :] = vehicle_kinematics(state[:5], action)
# other vehicle kinematics (constant velocity and steering)
state_dot[5:, :] = vehicle_kinematics(state[5:], [0, 0])
#construct
dynamics = Dynamics.SymContinuous(state_dot, state, action)
#Construct cost to overtake
px1, py1, heading1, vel1, steer1 = state[:5]
px2, py2, heading2, vel2, steer2 = state[5:]
#cost for reference lane
L = 0.2*(py1 - 1.5)**2
#cost on velocity
L += (vel1*sp.cos(heading1) - 2)**2 + (vel1 - 2)**2
#penality on actions
L += 0.1*action[1]**2 + 0.1*action[0]**2
#collision avoidance (do not cross ellipse around the vehicle)
L += SoftConstrain([((px1 - px2)/4.5)**2 + ((py1 - py2)/2)**2 - 1])
#constrain steering angle and y-position
L += Bounded([py1, steer1], high = [2.5, 0.523], low = [-2.5, -0.523])
#construct
cost = Cost.Symbolic(L, 0, state, action)
#initialise the controller
controller = iLQR(dynamics, cost)
#prediction Horizon
N = 200
#initial state
x0 = np.array([0, 1.5, 0, 1, 0,
4, 1.5, 0, 1, 0])
#initil guess
us_init = np.random.randn(N, n_u)*0.0001
#get optimal states and actions
xs, us, cost_trace = controller.fit(x0, us_init, 100)
#visualize the overtaking scenario
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.animation import FuncAnimation
from matplotlib.transforms import Affine2D
import numpy as np
def visualize(xs):
fig, ax = plt.subplots(figsize=(12, 6))
ax.set_xlim(0, 30)
ax.set_ylim(-3.1, 3.1)
ax.set_aspect('equal')
ax.axis("off")
for boundary_y in [-3, 3]:
ax.plot([0, 30], [boundary_y, boundary_y], 'k-', linewidth=1.0)
for lane_y in [0, 1.5]:
ax.plot([0, 30], [lane_y, lane_y], 'k--', linewidth=1.0)
ego_length = 2.0
ego_width = 1.0
other_length = 2.0
other_width = 1.0
ego_rect = patches.Rectangle((0, 0), ego_length, ego_width, fc='r', ec='r', alpha=0.5)
other_rect = patches.Rectangle((0, 0), other_length, other_width, fc='g', ec='g', alpha=0.5)
ax.add_patch(ego_rect)
ax.add_patch(other_rect)
ego_trajectory, = ax.plot([], [], 'r-', label='Ego vehicle trajectory')
other_trajectory, = ax.plot([], [], 'g-', label='Other vehicle trajectory')
def init():
ego_rect.set_xy((xs[0, 0] - ego_length / 2, xs[0, 1] - ego_width / 2))
ego_rect.angle = np.degrees(xs[0, 2])
other_rect.set_xy((xs[0, 5] - other_length / 2, xs[0, 6] - other_width / 2))
other_rect.angle = np.degrees(xs[0, 7])
ego_trajectory.set_data([], [])
other_trajectory.set_data([], [])
return ego_rect, other_rect, ego_trajectory, other_trajectory
def update(frame):
ego_center_x = xs[frame, 0]
ego_center_y = xs[frame, 1]
ego_angle = np.degrees(xs[frame, 2])
other_center_x = xs[frame, 5]
other_center_y = xs[frame, 6]
other_angle = np.degrees(xs[frame, 7])
ego_transform = Affine2D().rotate_deg_around(ego_center_x, ego_center_y, ego_angle) + ax.transData
ego_rect.set_transform(ego_transform)
ego_rect.set_xy((ego_center_x - ego_length / 2, ego_center_y - ego_width / 2))
other_transform = Affine2D().rotate_deg_around(other_center_x, other_center_y, other_angle) + ax.transData
other_rect.set_transform(other_transform)
other_rect.set_xy((other_center_x - other_length / 2, other_center_y - other_width / 2))
ego_trajectory.set_data(xs[:frame+1, 0], xs[:frame+1, 1])
other_trajectory.set_data(xs[:frame+1, 5], xs[:frame+1, 6])
return ego_rect, other_rect, ego_trajectory, other_trajectory
ani = FuncAnimation(fig, update, frames=range(len(xs)), init_func=init, blit=True, interval=50)
plt.xlabel('X position')
plt.ylabel('Y position')
plt.title('Vehicle Overtaking Visualization with Trajectories')
plt.legend()
plt.grid(True)
plt.show()
visualize(xs)