Skip to content

Commit e0cd780

Browse files
committed
add JuliaC example
1 parent 7a1c376 commit e0cd780

File tree

7 files changed

+103
-1
lines changed

7 files changed

+103
-1
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ julia = "1.7"
1313
AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a"
1414
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
1515
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
16+
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
1617
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1718

1819
[targets]
19-
test = ["AllocCheck", "Test", "ControlSystemsBase", "FixedPointNumbers"]
20+
test = ["AllocCheck", "Test", "ControlSystemsBase", "FixedPointNumbers", "JET"]

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ plot([res, res_fp], plotu=true, lab=["Float64" "" string(T) ""]); ylabel!("u + d
195195

196196
The fixed-point controller behaves roughly the same in this case, but artifacts are clearly visible. If the number of bits used for the fractional part is decreased, the controller will start to misbehave.
197197

198+
## Compilation using JuliaC
199+
The file `examples/juliac/juliac_pid.jl` contains a JuliaC-compatible interface that can be compiled into a C-callable shared library using JuliaC. To compile the file, run the following from the `examples/juliac` folder:
200+
```bash
201+
julia +nightly --project <PATH_TO_JULIA_REPO>/julia/contrib/juliac.jl --output-lib juliac_pid --trim=unsafe-warn --compile-ccallable juliac_pid.jl
202+
```
203+
where `<PATH_TO_JULIA_REPO>` should be replaced with the path to the Julia repository on your system. The command will generate a shared library `juliac_pid` that can be called from C. The file `examples/juliac/juliac_pid.h` contains the C-compatible interface to the shared library.
204+
205+
198206
## See also
199207
- [TrajectoryLimiters.jl](https://github.com/baggepinnen/TrajectoryLimiters.jl) To generate dynamically feasible reference trajectories with bounded velocity and acceleration given an instantaneous reference $r(t)$ which may change abruptly.
200208
- [SymbolicControlSystems.jl](https://github.com/JuliaControl/SymbolicControlSystems.jl) For C-code generation of LTI systems.

examples/juliac/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
3+
DiscretePIDs = "c1363496-6848-4723-8758-079b737f6baf"
4+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

examples/juliac/juliac_pid.jl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module JuliacPID
2+
import DiscretePIDs
3+
import DiscretePIDs: DiscretePID
4+
import Base.@ccallable
5+
6+
const T = Float64 # The numeric type used by the controller
7+
8+
# Set the initial PID parameters here
9+
const pid = DiscretePIDs.DiscretePID(; K = T(1), Ti = 1, Td = false, Ts = 1)
10+
11+
12+
@ccallable function calculate_control!(r::T, y::T, uff::T)::T
13+
DiscretePIDs.calculate_control!(pid, r, y, uff)::T
14+
end
15+
16+
function set_K!(K::T, r::T, y::T)::Cvoid
17+
DiscretePIDs.set_K!(pid, K, r, y)
18+
nothing
19+
end
20+
21+
function set_Ti!(Ti::T)::Cvoid
22+
DiscretePIDs.set_Ti!(pid, Ti)
23+
nothing
24+
end
25+
26+
function set_Td!(Td::T)::Cvoid
27+
DiscretePIDs.set_Td!(pid, Td)
28+
nothing
29+
end
30+
31+
@ccallable function reset_state!()::Cvoid
32+
DiscretePIDs.reset_state!(pid)
33+
nothing
34+
end
35+
36+
@ccallable function main()::Cint
37+
println(Core.stdout, "I'm alive and well")
38+
u = calculate_control!(0.0, 0.0, 0.0)
39+
println(Core.stdout, u)
40+
41+
Cint(0)
42+
end
43+
44+
45+
end
46+
47+
# compile using something like
48+
# cd(@__DIR__)
49+
# run(`julia +nightly --project --experimental /home/fredrikb/repos/julia/contrib/juliac.jl --output-lib juliac_pid --trim=unsafe-warn --compile-ccallable juliac_pid.jl`)
50+
# run(`ls -ltrh`) # marvel at the smallness of the binary

examples/juliac/test_juliac_pid.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Run this file with the same version of julia that you used to compile the shared library.
2+
cd(@__DIR__)
3+
4+
const T = Float64
5+
lib = Libc.Libdl.dlopen("/home/fredrikb/.julia/dev/DiscretePIDs/examples/juliac/juliac_pid.so")
6+
const calc = Libc.Libdl.dlsym(lib, :calculate_control!)
7+
8+
function pid(r::T, y::T, uff::T)
9+
ccall(calc, T, (T, T, T), r, y, uff)
10+
end
11+
12+
pid(0.0, 0.0, 0.0) # test
13+
14+
using ControlSystemsBase, Plots
15+
Tf = 15 # Simulation time
16+
Ts = 0.01 # sample time
17+
18+
P = c2d(ss(tf(1, [1, 1])), Ts) # Process to be controlled, discretized using zero-order hold
19+
20+
ctrl = function(x,t)
21+
y = (P.C*x)[] # measurement
22+
d = 1 # disturbance
23+
r = 0 # reference
24+
u = pid(T(r), T(y), T(0))
25+
u + d # Plant input is control signal + disturbance
26+
end
27+
28+
res = lsim(P, ctrl, Tf)
29+
30+
plot(res, plotu=true); ylabel!("u + d", sp=2)

src/DiscretePIDs.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ function set_K!(pid::DiscretePID, K, r, y)
124124
pid.bi = K * pid.Ts / pid.Ti
125125
pid.I = pid.I + Kold*(pid.b*r - y) - K*(pid.b*r - y)
126126
end
127+
nothing
127128
end
128129

129130
"""
@@ -139,6 +140,7 @@ function set_Ti!(pid::DiscretePID{T}, Ti) where T
139140
else
140141
pid.bi = zero(T)
141142
end
143+
nothing
142144
end
143145

144146
"""
@@ -151,6 +153,7 @@ function set_Td!(pid::DiscretePID, Td)
151153
pid.Td = Td
152154
pid.ad = Td / (Td + pid.N * pid.Ts)
153155
pid.bd = pid.K * pid.N * pid.ad
156+
nothing
154157
end
155158

156159

@@ -193,6 +196,7 @@ function reset_state!(pid::DiscretePID)
193196
pid.I = zero(pid.I)
194197
pid.D = zero(pid.D)
195198
pid.yold = zero(pid.yold)
199+
nothing
196200
end
197201

198202
end

test/runtests.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ using DiscretePIDs
22
using Test
33
using ControlSystemsBase
44
using AllocCheck
5+
using JET
56

67
@testset "DiscretePIDs.jl" begin
78

@@ -95,6 +96,10 @@ reset_state!(pid)
9596
res3 = lsim(P, ctrl, Tf)
9697
@test res3.y == res2.y
9798

99+
@test_opt pid(1.0, 1.0)
100+
@test_opt pid(1.0, 1.0, 1.0)
101+
# @report_call pid(1.0, 1.0)
102+
98103
## Test with FixedPointNumbers
99104
using FixedPointNumbers
100105
T = Fixed{Int16, 10} # 16-bit signed fixed-point with 10 bits for the fractional part

0 commit comments

Comments
 (0)