Custom SystemStructure and SymbolicAWESystem
A custom SystemStructure
can be used to create models of kite power systems of almost any configuration.
- custom amount of tethers
- custom bridle configurations
- quasi-static or dynamic point masses
- different amounts of stiffness, damping and diameter on different tether segments
Precondition
First, following the Home section up to the installation of the examples. To start Julia, either use julia --project=.
, or ./bin/run_julia
. Make sure that at least SymbolicAWEModels
version 0.2 is installed by typing ]status
in the Julia REPL. If necessary, update SymbolicAWEModels
by typing ]up
.
Creating a simple tether
We start by loading the necessary packages and defining settings and parameters.
using SymbolicAWEModels, VortexStepMethod, ControlPlots
set = Settings("system.yaml")
set.segments = 20
set.l_tether = 50.0
dynamics_type = DYNAMIC
Then, we define vectors of the system structure types we are going to use. For this simple example we only need points and segments.
points = Point[]
segments = Segment[]
points = push!(points, Point(1, zeros(3), STATIC; wing_idx=0))
The first point we add is a static point. There are four different DynamicsType
s to choose from: STATIC
, QUASI_STATIC
, DYNAMIC
and WING
. STATIC
just means that the point doesn't move. DYNAMIC
is a point modeled with acceleration, while QUASI_STATIC
constrains this acceleration to be zero at all times. A WING
point is connected to a wing body.
Now we can add DYNAMIC
points and connect them to each other with segments. BRIDLE
segments don't need to have a tether, because they have a constant unstretched length.
segment_idxs = Int[]
for i in 1:set.segments
global points, segments
point_idx = i+1
pos = [0.0, 0.0, i * set.l_tether / set.segments]
if i < set.segments
push!(points, Point(point_idx, pos, dynamics_type; wing_idx=0))
else
push!(points, Point(point_idx, pos, dynamics_type; mass=1.0, wing_idx=0))
end
segment_idx = i
push!(segments, Segment(segment_idx, set, (point_idx-1, point_idx), BRIDLE))
push!(segment_idxs, segment_idx)
end
In order to describe the initial orientation of the structure, we define a Transform(idx, elevation, azimuth, heading)
with an elevation (-80 degrees), azimuth and heading, and a base position [0.0, 0.0, 50.0]
.
transforms = [Transform(1, deg2rad(-80), 0.0, 0.0;
base_pos = [0.0, 0.0, 50.0], base_point_idx=points[1].idx,
rot_point_idx=points[end].idx)]
From the points, segments and transform we create a SystemStructure(name, set)
, which can be plotted in 2d to quickly investigate if the model is correct.
sys_struct = SystemStructure("tether", set; points, segments, transforms)
plot(sys_struct, 0.0)
If the system looks good, we can easily model it, by first creating a SymbolicAWEModel
, initializing it and stepping through time.
sam = SymbolicAWEModel(set, sys_struct)
init!(sam; remake=false)
for i in 1:80
plot(sam, i/set.sample_freq)
next_step!(sam)
end
Using a winch and a tether
Let's try to adjust the length of the tether in the last example. To do this we first need to create a set of segments with a common changing l0
, called a Tether
.
set.v_wind = 0.0
tethers = [Tether(1,[segment.idx for segment in segments])]
As you can see, we just add all of the segments from the simple tether to our Tether
struct. 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.
using WinchModels
wm = TorqueControlledMachine(set)
winches = [Winch(1, wm, [1])]
The 2d plot of the SystemStructure
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.
sys_struct = SystemStructure("winch", set; points, segments, tethers, winches, transforms)
@show set.v_wind
sam = SymbolicAWEModel(set, sys_struct)
init!(sam; remake=false)
ss = SysState(sam)
for i in 1:80
plot(sam, (i-1)/set.sample_freq)
next_step!(sam; set_values=[-20.0])
update_sys_state!(ss, sam)
end
@show ss.l_tether[1]
Using a pulley
First, we need to update some settings. l_tether
is specified such that the plot window is zoomed in correctly.
using SymbolicAWEModels, VortexStepMethod, ControlPlots
set = se("system.yaml")
set.v_wind = 10.0
set.l_tether = 5.0
set.abs_tol = 1e-4
set.rel_tol = 1e-4
dynamics_type = DYNAMIC
Now we create points and segments in a similar manner as in the last example. The mass
keyword can be used to specify the mass of the point itself. When mass=0.0
the mass of the point just consists of the tether/segment mass.
points = Point[]
segments = Segment[]
pulleys = Pulley[]
push!(points, Point(1, [0.0, 0.0, 2.0], STATIC))
push!(points, Point(2, [2.0, 0.0, 2.0], STATIC))
push!(points, Point(3, [0.1, 0.0, 1.0], DYNAMIC))
push!(points, Point(4, [0.1, 0.0, 0.0], DYNAMIC; mass=0.1))
push!(segments, Segment(1, set, (3,1), BRIDLE))
push!(segments, Segment(2, set, (3,2), BRIDLE))
push!(segments, Segment(3, set, (3,4), BRIDLE))
Pulleys can be modeled when three or more Segment
s are connected to a common Point
. When creating a pulley, only two segments are specified: these are the segments of the tether moving through the pulley.
push!(pulleys, Pulley(1, (1,2), DYNAMIC))
We can then use a Transform
to describe the orientation of the initial system.
transforms = [Transform(1, -deg2rad(0.0), 0.0, 0.0; base_pos=[1.0, 0.0, 4.0], base_point_idx=1, rot_point_idx=2)]
sys_struct = SymbolicAWEModels.SystemStructure("pulley", set; points, segments, pulleys, transforms)
plot(sys_struct, 0.0; zoom=false, l_tether=set.l_tether)
If the plot of the SystemStructure
looks good, we can continue by creating a SymbolicAWEModel
and simulating through time.
sam = SymbolicAWEModel(set, sys_struct)
init!(sam; remake=false)
for i in 1:100
plot(sam, i/set.sample_freq; zoom=false)
next_step!(sam)
end