Skip to content

Commit 2727b07

Browse files
authored
Merge pull request #113 from OpenSourceAWE/steady-torque
Add calc steady torque function and remove WinchModels dependency
2 parents 7c8b9f5 + 259148c commit 2727b07

File tree

12 files changed

+130
-93
lines changed

12 files changed

+130
-93
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
run: |
2828
docker run --rm --volume ${{ github.workspace }}:/data fsfe/reuse lint
2929
30-
test:
30+
test-with-code-coverage:
3131
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
3232
runs-on: ${{ matrix.os }}
3333
timeout-minutes: 120
@@ -86,41 +86,6 @@ jobs:
8686
if-no-files-found: ignore
8787
retention-days: 7
8888

89-
test-with-code-coverage:
90-
name: Julia 1.11 - ubuntu-latest - x64 - with code coverage
91-
runs-on: ubuntu-latest
92-
timeout-minutes: 120
93-
steps:
94-
- name: Checkout code
95-
uses: actions/checkout@v5
96-
with:
97-
ref: ${{ github.event.client_payload.ref || github.head_ref || github.ref }}
98-
99-
- name: Copy default Manifest files
100-
run: |
101-
cp Manifest-v1.11.toml.default Manifest.toml ||
102-
echo "No default available for Manifest-v1.11.toml"
103-
shell: bash
104-
105-
- name: Install matplotlib
106-
run: sudo apt-get install -y python3-matplotlib
107-
shell: bash
108-
109-
- uses: julia-actions/setup-julia@v2
110-
with:
111-
version: '1.11'
112-
arch: x64
113-
114-
- uses: julia-actions/cache@v2
115-
116-
- uses: julia-actions/julia-buildpkg@v1
117-
118-
- name: Build PyCall
119-
run: julia --project -e 'ENV["SAM_PRECOMPILE"]="false"; ENV["PYTHON"]=""; using Pkg; Pkg.instantiate(); Pkg.add("PyCall"); Pkg.build("PyCall")'
120-
shell: bash
121-
122-
- uses: julia-actions/julia-runtest@v1
123-
12489
- uses: julia-actions/julia-processcoverage@v1
12590

12691
- uses: codecov/codecov-action@v5

docs/src/exported_types.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ Pulley(idx, segment_idxs, type)
5656
Tether
5757
Tether(idx, segment_idxs, winch_idx)
5858
Winch
59-
Winch(idx, model, tether_idxs; tether_len, tether_vel, brake)
59+
Winch(idx, set::Settings, tether_idxs; tether_len, tether_vel, brake)
60+
Winch(idx, tether_idxs, gear_ratio, drum_radius, f_coulomb, c_vf, inertia_total; tether_len, tether_vel, brake)
6061
Wing
6162
Wing(idx, vsm_aero, vsm_wing, vsm_solver, group_idxs, R_b_c, pos_cad; transform_idx)
6263
Transform

docs/src/private_functions.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@ SymbolicAWEModels.get_sys_struct_hash
3737
## Physics and Geometry Helpers
3838

3939
```@docs
40-
SymbolicAWEModels.calc_speed_acc
41-
SymbolicAWEModels.calc_moment_acc
4240
SymbolicAWEModels.calc_angle_of_attack
4341
SymbolicAWEModels.calc_heading
4442
SymbolicAWEModels.calc_R_t_w
4543
SymbolicAWEModels.calc_R_v_w
4644
SymbolicAWEModels.cad_to_body_frame
4745
SymbolicAWEModels.calc_pos
46+
SymbolicAWEModels.calc_steady_torque
4847
SymbolicAWEModels.find_axis_point
4948
SymbolicAWEModels.quaternion_to_rotation_matrix
5049
SymbolicAWEModels.rotation_matrix_to_quaternion

docs/src/tutorial_system_structure.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ set.v_wind = 0.0
9191
tethers = [Tether(1,[segment.idx for segment in segments])]
9292
```
9393
As you can see, we just add all of the segments from the simple tether to our [`Tether`](@ref) struct.
94-
The next step is to create a winch. Each winch can be connected to one or more tethers, so it is possible to connect multiple tethers to the same winch. We have to specify which kind of winch we want to use. For now, only the `TorqueControlledMachine` from `WinchModels.jl` is supported.
94+
The next step is to create a winch. Each winch can be connected to one or more tethers, so it is possible to connect multiple tethers to the same winch.
95+
The winch is a torque controlled winch.
9596

9697
```julia
9798
using WinchModels
98-
wm = TorqueControlledMachine(set)
99-
winches = [Winch(1, wm, [1])]
99+
winches = [Winch(1, set, [1])]
100100
```
101101

102102
The 2d plot of the [`SystemStructure`](@ref) should still look the same, so we don't have to plot that. We can just create the system, and simulate it. We just need to be sure that we call plot with `t=0.0` to reset the plot.

examples/ram_air_kite.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ sam = SymbolicAWEModel(set)
2929
SymbolicAWEModels.init!(sam)
3030

3131
find_steady_state!(sam)
32-
bias = 0.15
32+
bias = 0.2
3333
if set.physical_model == "4_attach_ram"
3434
bias = 0.05
3535
end

src/generate_system.jl

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@
33

44
# Implementation of the ram air wing model using ModelingToolkit.jl
55

6-
"""
7-
calc_speed_acc(winch::AsyncMachine, tether_vel, norm_, set_speed)
8-
9-
Calculate winch acceleration for a speed-controlled asynchronous machine model.
10-
"""
11-
function calc_speed_acc(winch::AsyncMachine, tether_vel, norm_, set_speed)
12-
calc_acceleration(winch, tether_vel, norm_; set_speed, set_torque=nothing, use_brake=false) # TODO: add brake setting
13-
end
14-
15-
"""
16-
calc_moment_acc(winch::TorqueControlledMachine, tether_vel, norm_, set_torque)
17-
18-
Calculate winch acceleration for a torque-controlled machine model.
19-
"""
20-
function calc_moment_acc(winch::TorqueControlledMachine, tether_vel, norm_, set_torque)
21-
calc_acceleration(winch, tether_vel, norm_; set_speed=nothing, set_torque, use_brake=false)
22-
end
23-
246
"""
257
calc_angle_of_attack(va_wing_b)
268
@@ -184,6 +166,17 @@ get_fix_point_sphere(sys::SystemStructure, idx::Int16) = sys.points[idx].fix_sph
184166
get_fix_wing_sphere(sys::SystemStructure, idx::Int16) = sys.wings[idx].fix_sphere
185167
@register_symbolic get_fix_wing_sphere(sys::SystemStructure, idx::Int16)
186168

169+
get_winch_gear_ratio(sys::SystemStructure, idx::Int16) = sys.winches[idx].gear_ratio
170+
@register_symbolic get_winch_gear_ratio(sys::SystemStructure, idx::Int16)
171+
get_winch_drum_radius(sys::SystemStructure, idx::Int16) = sys.winches[idx].drum_radius
172+
@register_symbolic get_winch_drum_radius(sys::SystemStructure, idx::Int16)
173+
get_winch_f_coulomb(sys::SystemStructure, idx::Int16) = sys.winches[idx].f_coulomb
174+
@register_symbolic get_winch_f_coulomb(sys::SystemStructure, idx::Int16)
175+
get_winch_c_vf(sys::SystemStructure, idx::Int16) = sys.winches[idx].c_vf
176+
@register_symbolic get_winch_c_vf(sys::SystemStructure, idx::Int16)
177+
get_winch_inertia_total(sys::SystemStructure, idx::Int16) = sys.winches[idx].inertia_total
178+
@register_symbolic get_winch_inertia_total(sys::SystemStructure, idx::Int16)
179+
187180
get_set_mass(set::Settings) = set.mass
188181
@register_symbolic get_set_mass(set::Settings)
189182
get_rho_tether(set::Settings) = set.rho_tether
@@ -632,6 +625,12 @@ function force_eqs!(s, system, psys, pset, eqs, defaults, guesses;
632625
winch_force(t)[eachindex(winches)]
633626
winch_force_vec(t)[1:3, eachindex(winches)]
634627
brake(t)[eachindex(winches)]
628+
# New symbolic variables for winch dynamics
629+
ω_motor(t)[eachindex(winches)]
630+
tau_friction(t)[eachindex(winches)]
631+
tau_motor(t)[eachindex(winches)]
632+
tau_total(t)[eachindex(winches)]
633+
α_motor(t)[eachindex(winches)]
635634
end
636635
for winch in winches
637636
F = zeros(Num, 3)
@@ -641,6 +640,18 @@ function force_eqs!(s, system, psys, pset, eqs, defaults, guesses;
641640
error("Point number $winch_idx does not exist.")
642641
F .+= point_force[:, winch_idx]
643642
end
643+
644+
gear_ratio = get_winch_gear_ratio(psys, winch.idx)
645+
drum_radius = get_winch_drum_radius(psys, winch.idx)
646+
f_coulomb = get_winch_f_coulomb(psys, winch.idx)
647+
c_vf = get_winch_c_vf(psys, winch.idx)
648+
inertia_total = get_winch_inertia_total(psys, winch.idx)
649+
650+
function smooth_sign(x)
651+
EPSILON = 6
652+
x / sqrt(x * x + EPSILON * EPSILON)
653+
end
654+
644655
eqs = [
645656
eqs
646657
brake[winch.idx] ~ get_brake(psys, winch.idx)
@@ -649,11 +660,18 @@ function force_eqs!(s, system, psys, pset, eqs, defaults, guesses;
649660
D(tether_vel[winch.idx]) ~ ifelse(brake[winch.idx]==true,
650661
0, tether_acc[winch.idx])
651662

652-
tether_acc[winch.idx] ~ calc_moment_acc( # TODO: moment and speed control
653-
winch.model, tether_vel[winch.idx],
654-
winch_force[winch.idx],
655-
set_values[winch.idx]
656-
)
663+
# Symbolic winch dynamics equations
664+
ω_motor[winch.idx] ~ gear_ratio / drum_radius * tether_vel[winch.idx]
665+
tau_friction[winch.idx] ~ smooth_sign(ω_motor[winch.idx]) *
666+
f_coulomb * drum_radius / gear_ratio +
667+
c_vf * ω_motor[winch.idx] * drum_radius^2 / gear_ratio^2
668+
tau_motor[winch.idx] ~ set_values[winch.idx] # set_value is the motor torque
669+
tau_total[winch.idx] ~ tau_motor[winch.idx] +
670+
drum_radius / gear_ratio * winch_force[winch.idx] -
671+
tau_friction[winch.idx]
672+
α_motor[winch.idx] ~ tau_total[winch.idx] / inertia_total
673+
tether_acc[winch.idx] ~ drum_radius / gear_ratio * α_motor[winch.idx]
674+
657675
winch_force_vec[:, winch.idx] ~ F
658676
winch_force[winch.idx] ~ norm(winch_force_vec[:, winch.idx])
659677
]

src/model_management.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ function generate_prob_getters(sys_struct, sys)
3737
if length(groups) > 0; get_group_state = getu(sys, c.([sys.twist_angle, sys.twist_ω, sys.group_tether_force, sys.group_tether_moment, sys.group_aero_moment])); end
3838
if length(pulleys) > 0; get_pulley_state = getu(sys, c.([sys.pulley_len, sys.pulley_vel])); end
3939
if length(winches) > 0
40-
get_winch_state = getu(sys, c.([sys.tether_len, sys.tether_vel, sys.set_values, sys.winch_force_vec]))
40+
get_winch_state = getu(sys, c.([sys.tether_len, sys.tether_vel, sys.set_values,
41+
sys.winch_force_vec, sys.tau_friction]))
4142
set_set_values = setp(sys, sys.set_values)
4243
get_set_values = getp(sys, sys.set_values)
4344
end
@@ -509,8 +510,7 @@ function get_sys_struct_hash(sys_struct::SystemStructure)
509510
push!(data_parts, ("tether", tether.idx, tether.segment_idxs))
510511
end
511512
for winch in winches
512-
model_type = winch.model isa TorqueControlledMachine
513-
push!(data_parts, ("winch", winch.idx, model_type, winch.tether_idxs))
513+
push!(data_parts, ("winch", winch.idx, winch.tether_idxs))
514514
end
515515
for wing in wings
516516
push!(data_parts, ("wing", wing.idx, wing.group_idxs))

src/predefined_structures.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,9 @@ function create_4_attach_ram_sys_struct(set::Settings)
156156
STEERING_LINE, dynamics_type; z)
157157

158158
winches = [
159-
Winch(1, TorqueControlledMachine(set), [left_power_idx, right_power_idx])
160-
Winch(2, TorqueControlledMachine(set), [left_steering_idx])
161-
Winch(3, TorqueControlledMachine(set), [right_steering_idx])
159+
Winch(1, set, [left_power_idx, right_power_idx])
160+
Winch(2, set, [left_steering_idx])
161+
Winch(3, set, [right_steering_idx])
162162
]
163163

164164
vsm_aero = BodyAerodynamics([vsm_wing])
@@ -299,9 +299,9 @@ function create_ram_sys_struct(set::Settings)
299299
STEERING_LINE, dynamics_type; z)
300300

301301
winches = [
302-
Winch(1, TorqueControlledMachine(set), [left_power_idx, right_power_idx])
303-
Winch(2, TorqueControlledMachine(set), [left_steering_idx])
304-
Winch(3, TorqueControlledMachine(set), [right_steering_idx])
302+
Winch(1, set, [left_power_idx, right_power_idx])
303+
Winch(2, set, [left_steering_idx])
304+
Winch(3, set, [right_steering_idx])
305305
]
306306

307307
vsm_aero = BodyAerodynamics([vsm_wing])
@@ -361,9 +361,9 @@ function create_tether_sys_struct(set::Settings;
361361
axial_stiffness=axial_stiffness[4], axial_damping=axial_damping[4])
362362

363363
winches = [
364-
Winch(1, TorqueControlledMachine(set), [left_power_idx, right_power_idx]; brake=true)
365-
Winch(2, TorqueControlledMachine(set), [left_steering_idx]; brake=true)
366-
Winch(3, TorqueControlledMachine(set), [right_steering_idx]; brake=true)
364+
Winch(1, set, [left_power_idx, right_power_idx]; brake=true)
365+
Winch(2, set, [left_steering_idx]; brake=true)
366+
Winch(3, set, [right_steering_idx]; brake=true)
367367
]
368368

369369
transforms = [Transform(1, deg2rad(set.elevation), deg2rad(set.azimuth), deg2rad(set.heading);
@@ -433,9 +433,9 @@ function create_simple_ram_sys_struct(set::Settings;
433433
Tether(4, [4], 8)
434434
]
435435
winches = [
436-
Winch(1, TorqueControlledMachine(set), [1,2])
437-
Winch(2, TorqueControlledMachine(set), [3])
438-
Winch(3, TorqueControlledMachine(set), [4])
436+
Winch(1, set, [1,2])
437+
Winch(2, set, [3])
438+
Winch(3, set, [4])
439439
]
440440
vsm_aero = BodyAerodynamics([vsm_wing])
441441
vsm_solver = Solver(vsm_aero; solver_type=NONLIN, atol=2e-8, rtol=2e-8)

src/simulate.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ function sim!(
3232
total_time=10.0,
3333
vsm_interval=3,
3434
prn=true,
35-
lin_model::Union{Nothing, <:NamedTuple, StateSpace}=nothing
35+
lin_model::Union{Nothing, <:NamedTuple, StateSpace}=nothing,
36+
torque_damp=0.9,
3637
)
3738
steps = Int(round(total_time / dt))
3839
sys_struct = sam.sys_struct
@@ -55,12 +56,14 @@ function sim!(
5556
set_torques = similar(set_values)
5657
y_op = sam.simple_lin_model.get_y(sam.integrator)
5758

59+
steady_torque = calc_steady_torque(sam)
60+
5861
# --- Nonlinear Simulation Loop ---
5962
elapsed = @elapsed for step in 1:steps
6063
t = (step-1) * dt
6164

62-
set_torques[step, :] = -sam.set.drum_radius .* [norm(winch.force) for winch in sys_struct.winches]
63-
set_torques[step, :] .+= set_values[step, :]
65+
steady_torque = torque_damp * steady_torque + (1-torque_damp) * calc_steady_torque(sam)
66+
set_torques[step, :] = steady_torque .+ set_values[step, :]
6467

6568
try
6669
step_time += @elapsed next_step!(sam;

src/symbolic_awe_model.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,13 @@ function update_sys_struct!(prob::ProbWithAttributes,
481481
end
482482
end
483483
if length(winches) > 0
484-
tether_len, tether_vel, set_value, winch_force_vec = prob.get_winch_state(integ)
484+
tether_len, tether_vel, set_value, winch_force_vec, friction = prob.get_winch_state(integ)
485485
for winch in winches
486486
winch.tether_len = tether_len[winch.idx]
487487
winch.tether_vel = tether_vel[winch.idx]
488488
winch.set_value = set_value[winch.idx]
489489
winch.force .= winch_force_vec[:, winch.idx]
490+
winch.friction = friction[winch.idx]
490491
end
491492
end
492493
if length(tethers) > 0
@@ -545,6 +546,18 @@ function get_model_name(set::Settings; precompile=false)
545546
return "model_$(ver)_$(set.physical_model)_$(dynamics_type)_$(set.segments)_seg.bin$suffix"
546547
end
547548

549+
"""
550+
calc_steady_torque(sam::SymbolicAWEModel)
551+
552+
Calculates the torque for each winch that results in zero acceleration (steady state).
553+
"""
554+
function calc_steady_torque(sam::SymbolicAWEModel)
555+
sys_struct = sam.sys_struct
556+
torques = -[winch.drum_radius / winch.gear_ratio * norm(winch.force) +
557+
winch.friction for winch in sys_struct.winches]
558+
return torques
559+
end
560+
548561
"""
549562
calc_aoa(s::SymbolicAWEModel)
550563

0 commit comments

Comments
 (0)