Skip to content

Commit d574d82

Browse files
author
Shunichi09
committed
ADD: added iLQR and DDP
1 parent abb4d75 commit d574d82

File tree

15 files changed

+1127
-41
lines changed

15 files changed

+1127
-41
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ celerybeat.pid
109109
# Environments
110110
.env
111111
.venv
112-
env/
113112
venv/
114113
ENV/
115114
env.bak/

PythonLinearNonlinearControl/configs/first_order_lag.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,19 @@ def __init__(self):
4343
"kappa": 0.9,
4444
"noise_sigma": 0.5,
4545
},
46-
"iLQR":{
47-
},
48-
"cgmres-NMPC":{
49-
},
50-
"newton-NMPC":{
51-
},
46+
"MPC":{
47+
}
5248
}
5349

5450
@staticmethod
5551
def input_cost_fn(u):
5652
""" input cost functions
5753
Args:
58-
u (numpy.ndarray): input, shape(input_size, )
59-
or shape(pop_size, input_size)
54+
u (numpy.ndarray): input, shape(pred_len, input_size)
55+
or shape(pop_size, pred_len, input_size)
6056
Returns:
61-
cost (numpy.ndarray): cost of input, none or shape(pop_size, )
57+
cost (numpy.ndarray): cost of input, shape(pred_len, input_size) or
58+
shape(pop_size, pred_len, input_size)
6259
"""
6360
return (u**2) * np.diag(FirstOrderLagConfigModule.R)
6461

@@ -67,11 +64,12 @@ def state_cost_fn(x, g_x):
6764
""" state cost function
6865
Args:
6966
x (numpy.ndarray): state, shape(pred_len, state_size)
70-
or shape(pop_size, pred_len, state_size)
71-
g_x (numpy.ndarray): goal state, shape(state_size, )
72-
or shape(pop_size, state_size)
67+
or shape(pop_size, pred_len, state_size)
68+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
69+
or shape(pop_size, pred_len, state_size)
7370
Returns:
74-
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
71+
cost (numpy.ndarray): cost of state, shape(pred_len, state_size) or
72+
shape(pop_size, pred_len, state_size)
7573
"""
7674
return ((x - g_x)**2) * np.diag(FirstOrderLagConfigModule.Q)
7775

@@ -84,7 +82,8 @@ def terminal_state_cost_fn(terminal_x, terminal_g_x):
8482
terminal_g_x (numpy.ndarray): terminal goal state,
8583
shape(state_size, ) or shape(pop_size, state_size)
8684
Returns:
87-
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
85+
cost (numpy.ndarray): cost of state, shape(pred_len, ) or
86+
shape(pop_size, pred_len)
8887
"""
8988
return ((terminal_x - terminal_g_x)**2) \
9089
* np.diag(FirstOrderLagConfigModule.Sf)

PythonLinearNonlinearControl/configs/two_wheeled.py

Lines changed: 116 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ class TwoWheeledConfigModule():
55
ENV_NAME = "TwoWheeled-v0"
66
TYPE = "Nonlinear"
77
TASK_HORIZON = 1000
8-
PRED_LEN = 10
8+
PRED_LEN = 20
99
STATE_SIZE = 3
1010
INPUT_SIZE = 2
1111
DT = 0.01
1212
# cost parameters
13-
R = np.eye(INPUT_SIZE)
14-
Q = np.eye(STATE_SIZE)
13+
R = np.eye(INPUT_SIZE) * 0.1
14+
Q = np.eye(STATE_SIZE) * 0.5
1515
Sf = np.eye(STATE_SIZE)
1616
# bounds
1717
INPUT_LOWER_BOUND = np.array([-1.5, 3.14])
@@ -40,34 +40,50 @@ def __init__(self):
4040
"noise_sigma": 0.5,
4141
},
4242
"iLQR":{
43+
"max_iter": 500,
44+
"mu": 1.,
45+
"mu_min": 1e-6,
46+
"mu_max": 1e10,
47+
"init_delta": 2.,
48+
"threshold": 1e-6,
49+
},
50+
"DDP":{
51+
"max_iter": 500,
52+
"mu": 1.,
53+
"mu_min": 1e-6,
54+
"mu_max": 1e10,
55+
"init_delta": 2.,
56+
"threshold": 1e-6,
4357
},
4458
"NMPC-CGMRES":{
4559
},
4660
"NMPC-Newton":{
4761
},
48-
}
62+
}
4963

5064
@staticmethod
5165
def input_cost_fn(u):
5266
""" input cost functions
5367
Args:
54-
u (numpy.ndarray): input, shape(input_size, )
55-
or shape(pop_size, input_size)
68+
u (numpy.ndarray): input, shape(pred_len, input_size)
69+
or shape(pop_size, pred_len, input_size)
5670
Returns:
57-
cost (numpy.ndarray): cost of input, none or shape(pop_size, )
71+
cost (numpy.ndarray): cost of input, shape(pred_len, input_size) or
72+
shape(pop_size, pred_len, input_size)
5873
"""
59-
return (u**2) * np.diag(TwoWheeledConfigModule.R) * 0.1
74+
return (u**2) * np.diag(TwoWheeledConfigModule.R)
6075

6176
@staticmethod
6277
def state_cost_fn(x, g_x):
6378
""" state cost function
6479
Args:
6580
x (numpy.ndarray): state, shape(pred_len, state_size)
66-
or shape(pop_size, pred_len, state_size)
67-
g_x (numpy.ndarray): goal state, shape(state_size, )
68-
or shape(pop_size, state_size)
81+
or shape(pop_size, pred_len, state_size)
82+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
83+
or shape(pop_size, pred_len, state_size)
6984
Returns:
70-
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
85+
cost (numpy.ndarray): cost of state, shape(pred_len, state_size) or
86+
shape(pop_size, pred_len, state_size)
7187
"""
7288
return ((x - g_x)**2) * np.diag(TwoWheeledConfigModule.Q)
7389

@@ -80,7 +96,93 @@ def terminal_state_cost_fn(terminal_x, terminal_g_x):
8096
terminal_g_x (numpy.ndarray): terminal goal state,
8197
shape(state_size, ) or shape(pop_size, state_size)
8298
Returns:
83-
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
99+
cost (numpy.ndarray): cost of state, shape(pred_len, ) or
100+
shape(pop_size, pred_len)
84101
"""
85102
return ((terminal_x - terminal_g_x)**2) \
86-
* np.diag(TwoWheeledConfigModule.Sf)
103+
* np.diag(TwoWheeledConfigModule.Sf)
104+
105+
@staticmethod
106+
def gradient_cost_fn_with_state(x, g_x, terminal=False):
107+
""" gradient of costs with respect to the state
108+
109+
Args:
110+
x (numpy.ndarray): state, shape(pred_len, state_size)
111+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
112+
113+
Returns:
114+
l_x (numpy.ndarray): gradient of cost, shape(pred_len, state_size)
115+
or shape(1, state_size)
116+
"""
117+
if not terminal:
118+
return 2. * (x - g_x) * np.diag(TwoWheeledConfigModule.Q)
119+
120+
return (2. * (x - g_x) \
121+
* np.diag(TwoWheeledConfigModule.Sf))[np.newaxis, :]
122+
123+
@staticmethod
124+
def gradient_cost_fn_with_input(x, u):
125+
""" gradient of costs with respect to the input
126+
127+
Args:
128+
x (numpy.ndarray): state, shape(pred_len, state_size)
129+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
130+
131+
Returns:
132+
l_u (numpy.ndarray): gradient of cost, shape(pred_len, input_size)
133+
"""
134+
return 2. * u * np.diag(TwoWheeledConfigModule.R)
135+
136+
@staticmethod
137+
def hessian_cost_fn_with_state(x, g_x, terminal=False):
138+
""" hessian costs with respect to the state
139+
140+
Args:
141+
x (numpy.ndarray): state, shape(pred_len, state_size)
142+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
143+
144+
Returns:
145+
l_xx (numpy.ndarray): gradient of cost,
146+
shape(pred_len, state_size, state_size) or
147+
shape(1, state_size, state_size) or
148+
"""
149+
if not terminal:
150+
(pred_len, _) = x.shape
151+
return -g_x[:, :, np.newaxis] \
152+
* np.tile(2.*TwoWheeledConfigModule.Q, (pred_len, 1, 1))
153+
154+
return -g_x[:, np.newaxis] \
155+
* np.tile(2.*TwoWheeledConfigModule.Sf, (1, 1, 1))
156+
157+
@staticmethod
158+
def hessian_cost_fn_with_input(x, u):
159+
""" hessian costs with respect to the input
160+
161+
Args:
162+
x (numpy.ndarray): state, shape(pred_len, state_size)
163+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
164+
165+
Returns:
166+
l_uu (numpy.ndarray): gradient of cost,
167+
shape(pred_len, input_size, input_size)
168+
"""
169+
(pred_len, _) = u.shape
170+
171+
return np.tile(2.*TwoWheeledConfigModule.R, (pred_len, 1, 1))
172+
173+
@staticmethod
174+
def hessian_cost_fn_with_input_state(x, u):
175+
""" hessian costs with respect to the state and input
176+
177+
Args:
178+
x (numpy.ndarray): state, shape(pred_len, state_size)
179+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
180+
181+
Returns:
182+
l_ux (numpy.ndarray): gradient of cost ,
183+
shape(pred_len, input_size, state_size)
184+
"""
185+
(_, state_size) = x.shape
186+
(pred_len, input_size) = u.shape
187+
188+
return np.zeros((pred_len, input_size, state_size))

PythonLinearNonlinearControl/controllers/controller.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ def obtain_sol(self, curr_x, g_xs):
2424
Returns:
2525
opt_input (numpy.ndarray): optimal input, shape(input_size, )
2626
"""
27-
raise NotImplementedError("Implement gradient of hamitonian with respect to the state")
27+
raise NotImplementedError("Implement the algorithm to \
28+
get optimal input")
2829

2930
def calc_cost(self, curr_x, samples, g_xs):
3031
""" calculate the cost of input samples

0 commit comments

Comments
 (0)