|
| 1 | +""" |
| 2 | +A collection of generic control components |
| 3 | +
|
| 4 | +Components: |
| 5 | +
|
| 6 | +- Integrator |
| 7 | +- UnitDelay |
| 8 | +- RateLimiter |
| 9 | +- Mixer_2CH two channel mixer |
| 10 | +- Mixer_3CH three channel mixer |
| 11 | +""" |
| 12 | + |
| 13 | +# Discrete integrator with external reset |
| 14 | +@with_kw mutable struct Integrator @deftype Float64 |
| 15 | + dt # timestep [s] |
| 16 | + i = 1.0 # integration constant |
| 17 | + output = 0.0 |
| 18 | + last_output = 0.0 |
| 19 | +end |
| 20 | + |
| 21 | +function Integrator(dt, i=1.0, x0=0.0) |
| 22 | + Integrator(dt, i, x0, x0) |
| 23 | +end |
| 24 | + |
| 25 | +function reset(int::Integrator, x0=0.0) |
| 26 | + int.output = x0 |
| 27 | + int.last_output = x0 |
| 28 | + nothing |
| 29 | +end |
| 30 | + |
| 31 | +function calc_output(int::Integrator, input) |
| 32 | + int.output = int.last_output + input * int.i * int.dt |
| 33 | +end |
| 34 | + |
| 35 | +function on_timer(int::Integrator) |
| 36 | + int.last_output = int.output |
| 37 | + nothing |
| 38 | +end |
| 39 | + |
| 40 | +# UnitDelay, delay the input signal by one time step. |
| 41 | +@with_kw mutable struct UnitDelay @deftype Float64 |
| 42 | + last_output = 0 |
| 43 | + last_input = 0 |
| 44 | +end |
| 45 | + |
| 46 | +function calc_output(ud::UnitDelay, input) |
| 47 | + ud.last_input = input |
| 48 | + ud.last_output |
| 49 | +end |
| 50 | + |
| 51 | +function on_timer(ud::UnitDelay) |
| 52 | + ud.last_output = ud.last_input |
| 53 | +end |
| 54 | + |
| 55 | +function reset(ud::UnitDelay) |
| 56 | + ud.last_input = 0.0 |
| 57 | + ud.last_output = 0.0 |
| 58 | +end |
| 59 | + |
| 60 | +# RateLimiter |
| 61 | +# Limit the rate of change of the output signal (return value of calc_output) to ± limit. |
| 62 | +# Unit of limit: 1/s |
| 63 | +@with_kw mutable struct RateLimiter @deftype Float64 |
| 64 | + dt = 0.05 |
| 65 | + limit = 1 |
| 66 | + output = 0 |
| 67 | + last_output = 0 |
| 68 | +end |
| 69 | + |
| 70 | +function RateLimiter(dt, limit=1.0, x0=0.0) |
| 71 | + RateLimiter(dt, limit, x0, x0) |
| 72 | +end |
| 73 | + |
| 74 | +function reset(ud::RateLimiter, x0=0.0) |
| 75 | + ud.output = x0 |
| 76 | + ud.last_output = x0 |
| 77 | +end |
| 78 | + |
| 79 | +function calc_output(rl::RateLimiter, input) |
| 80 | + if input - rl.last_output > rl.limit * rl.dt |
| 81 | + rl.output = rl.last_output + rl.limit * rl.dt |
| 82 | + elseif input - rl.last_output < -rl.limit * rl.dt |
| 83 | + rl.output = rl.last_output - rl.limit * rl.dt |
| 84 | + else |
| 85 | + rl.output = input |
| 86 | + end |
| 87 | + rl.output |
| 88 | +end |
| 89 | + |
| 90 | +function on_timer(rl::RateLimiter) |
| 91 | + rl.last_output = rl.output |
| 92 | +end |
| 93 | + |
| 94 | +# Mixer_2CH |
| 95 | +# Mix two analog inputs. Implements the simulink block diagram, shown in |
| 96 | +# docs/mixer_2ch.png |
| 97 | +@with_kw mutable struct Mixer_2CH @deftype Float64 |
| 98 | + dt |
| 99 | + t_blend = 1.0 |
| 100 | + factor_b = 0 |
| 101 | + select_b::Bool = false |
| 102 | +end |
| 103 | + |
| 104 | +function Mixer_2CH(dt, t_blend) |
| 105 | + Mixer_2CH(dt, t_blend, 0, false) |
| 106 | +end |
| 107 | + |
| 108 | +function select_b(m2::Mixer_2CH, select_b::Bool) |
| 109 | + m2.select_b = select_b |
| 110 | +end |
| 111 | + |
| 112 | +function on_timer(m2::Mixer_2CH) |
| 113 | + if m2.select_b |
| 114 | + integrator_in = 1.0 / m2.t_blend |
| 115 | + else |
| 116 | + integrator_in = -1.0 / m2.t_blend |
| 117 | + end |
| 118 | + m2.factor_b += integrator_in * m2.dt |
| 119 | + m2.factor_b = saturate(m2.factor_b, 0, 1) |
| 120 | +end |
| 121 | + |
| 122 | +function calc_output(m2::Mixer_2CH, input_a, input_b) |
| 123 | + input_b * m2.factor_b + input_a * (1.0 - m2.factor_b) |
| 124 | +end |
| 125 | + |
| 126 | +# Mixer_3CH |
| 127 | +# Mix three analog inputs. Implements the simulink block diagram, shown in |
| 128 | +# docs/mixer_3ch.png |
| 129 | +@with_kw mutable struct Mixer_3CH @deftype Float64 |
| 130 | + dt |
| 131 | + t_blend = 1.0 |
| 132 | + factor_b = 0 |
| 133 | + factor_c = 0 |
| 134 | + select_b::Bool = false |
| 135 | + select_c::Bool = false |
| 136 | +end |
| 137 | + |
| 138 | +function Mixer_3CH(dt, t_blend = 1.0) |
| 139 | + Mixer_3CH(dt, t_blend, 0, 0, false, false) |
| 140 | +end |
| 141 | + |
| 142 | +function on_timer(m3::Mixer_3CH) |
| 143 | + # calc output of integrator b |
| 144 | + if m3.select_b |
| 145 | + integrator_b_in = 1.0 / m3.t_blend |
| 146 | + else |
| 147 | + integrator_b_in = -1.0 / m3.t_blend |
| 148 | + end |
| 149 | + m3.factor_b += integrator_b_in * m3.dt |
| 150 | + m3.factor_b = saturate(m3.factor_b, 0, 1) |
| 151 | + # calc output of integrator c |
| 152 | + if m3.select_c |
| 153 | + integrator_c_in = 1.0 / m3.t_blend |
| 154 | + else |
| 155 | + integrator_c_in = -1.0 / m3.t_blend |
| 156 | + end |
| 157 | + m3.factor_c += integrator_c_in * m3.dt |
| 158 | + m3.factor_c = saturate(m3.factor_c, 0, 1) |
| 159 | + nothing |
| 160 | +end |
| 161 | + |
| 162 | +function select_b(m3::Mixer_3CH, select_b::Bool) |
| 163 | + m3.select_b = select_b |
| 164 | + if select_b |
| 165 | + select_c(m3, false) |
| 166 | + end |
| 167 | +end |
| 168 | + |
| 169 | +function select_c(m3::Mixer_3CH, select_c::Bool) |
| 170 | + m3.select_c = select_c |
| 171 | + if select_c |
| 172 | + select_b(m3, false) |
| 173 | + end |
| 174 | +end |
| 175 | + |
| 176 | +function calc_output(m3::Mixer_3CH, input_a, input_b, input_c) |
| 177 | + input_b * m3.factor_b + input_c * m3.factor_c + input_a * (1.0 - m3.factor_b - m3.factor_c) |
| 178 | +end |
| 179 | + |
| 180 | +""" |
| 181 | +Return the controller state as integer. |
| 182 | +
|
| 183 | +wcsLowerForceControl = 0 # input b selected |
| 184 | +wcsSpeedControl = 1 # input a selected |
| 185 | +wcsUpperForceControl = 2 # input c selected |
| 186 | +""" |
| 187 | +function get_state(m3::Mixer_3CH) |
| 188 | + Int(! m3.select_b && ! m3.select_c) + 2 * Int(m3.select_c) |
| 189 | +end |
0 commit comments