Skip to content

Commit 9529eae

Browse files
committed
doc: simple code generation example in manual
1 parent 926e12d commit 9529eae

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

docs/src/manual/linmpc.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,68 @@ savefig("plot4_LinMPC.svg"); nothing # hide
293293
Note that measured disturbances are assumed constant in the future by default but custom
294294
``\mathbf{D̂}`` predictions are possible. The same applies for the setpoint predictions
295295
``\mathbf{R̂_y}``.
296+
297+
## Generating C code
298+
299+
The [`LinearMPC.jl`](@extref LinearMPC) package extension provides code generation
300+
capabilities to export the controller as optimized C code. First, install the package with:
301+
302+
```test
303+
using Pkg; Pkg.add("LinearMPC")
304+
```
305+
306+
The feedforward MPC controller can be converted to a [`LinearMPC.MPC`](@ref) object using:
307+
308+
```@example 1
309+
import LinearMPC
310+
c_mpc_d = LinearMPC.MPC(mpc_d);
311+
```
312+
313+
We test the converted controller in closed-loop to verify that it behaves identically to the
314+
original one:
315+
316+
```@example 1
317+
function test_c_mpc_d(c_mpc_d, model)
318+
N = 200
319+
ry, ul = [50, 30], 0
320+
dop = 20
321+
u = model.uop
322+
u_data, y_data, ry_data = zeros(model.nu, N), zeros(model.ny, N), zeros(model.ny, N)
323+
for i = 1:N
324+
i == 51 && (ry = [50, 35])
325+
i == 101 && (ry = [54, 30])
326+
i == 151 && (ul = -20)
327+
d = [ul .+ dop]
328+
y = model()
329+
x̂ = LinearMPC.correct_state!(c_mpc_d, y, d)
330+
u = LinearMPC.compute_control(c_mpc_d, x̂; r=ry, d=d, uprev=u)
331+
u_data[:,i], y_data[:,i], ry_data[:,i] = u, y, ry
332+
LinearMPC.predict_state!(c_mpc_d, u, d)
333+
updatestate!(model, u + [0; ul])
334+
end
335+
return u_data, y_data, ry_data
336+
end
337+
setstate!(model, zeros(model.nx))
338+
LinearMPC.set_state!(c_mpc_d, zeros(c_mpc_d.model.nx))
339+
u_data, y_data, ry_data = test_c_mpc_d(c_mpc_d, model)
340+
plot_data(t_data, u_data, y_data, ry_data)
341+
savefig("plot5_LinMPC.svg"); nothing # hide
342+
```
343+
344+
![plot5_LinMPC](plot5_LinMPC.svg)
345+
346+
The closed-loop simulation matches the results of the previous section, as expected. We
347+
can now generate the C code using:
348+
349+
```julia
350+
LinearMPC.codegen(c_mpc_d; dir="codegen", fname="mpc_funcs")
351+
```
352+
353+
The three C functions to call at each control periods are declared in the generated file
354+
`codegen/mpc_funcs.h`:
355+
356+
```C
357+
void mpc_correct_state(c_float* state, c_float* measurement, c_float* distrubance);
358+
int mpc_compute_control(c_float* control, c_float* state, c_float* reference, c_float* disturbance);
359+
void mpc_predict_state(c_float* state, c_float* control, c_float* disturbance);
360+
```

0 commit comments

Comments
 (0)