Skip to content

State-estimation example #177

@baggepinnen

Description

@baggepinnen

This may run after the quad example, it estimates an unknown load mass

using LowLevelParticleFilters, SeeToDee, StaticArrays

Ts = 0.02
tv = range(0, 7, step=Ts)
Y = [SVector(i...) .+ 0.01 .* randn.() for i in sol(tv, idxs=outputs)]
Y0 = [SVector(i...) for i in sol(tv, idxs=outputs)]
U = [SVector(i...) .+ 0.2 .* randn.() for i in sol(tv, idxs=inputs)]
X = Matrix(sol(tv, idxs=x_sym))
##

state_parameters = [quad.body.m]

function dyn_with_state_parameters(mmodel, inputs, state_parameters)
    fdyn, x_sym, p_sym, io_sys = ModelingToolkit.generate_control_function(mmodel, inputs)

    p_inds = [findfirst(x -> string(x) == string(p), p_sym) for p in state_parameters]
    # @info "found" p_sym[p_inds]

    nx_orig = length(x_sym)
    nx_extended = nx_orig + length(state_parameters)

    p1 = copy(p)
    dx = zeros(nx_orig)
    out = zeros(nx_extended)

    f_ext = function (x, u, p, t)
        for (i, p_ind) in enumerate(p_inds)
            p1[p_ind] = max(x[nx_orig + i], 0.1) # NOTE: temp hack
        end
        dx .= 0
        fdyn(dx, x, u, p1, t)
        @views out[1:nx_orig] .= dx
        # [dx; x[nx_orig+1:end]]
        @views out[nx_orig+1:end] .= x[nx_orig+1:end]
        out
    end
    # f_ext, [x_sym; p_sym[p_inds]], p_sym[1:end-length(inputs)], io_sys
    f_ext, [x_sym; p_sym[p_inds]], p_sym, io_sys
end

fdyn, x_sym, p_sym, io_sys = dyn_with_state_parameters(multibody(quad), inputs, state_parameters)

g = JuliaSimCompiler.build_explicit_observed_function(io_sys, outputs; inputs)
nx = length(x_sym)
nu = length(inputs)
ny = length(outputs)
x = randn(nx)
u = randn(nu)

op = [
    quad.body.r_0[2] => 1e-32
    quad.v_alt => 1e-32 # To avoid singularity in linearization
    quad.world.g => 9.81
    inputs .=> 13;
    quad.body.m => 2 # We pretend that the body mass is close to cable+load+body mass for better altitude estimation
] |> Dict
##
x0, p = JuliaSimCompiler.initial_conditions(io_sys, op, op)
y0 = g(x0, u, p, 0)
R1 = collect(0.001I(nx))
R1[end] = 0.01
R2 = 0.01^2 * I(ny)

d0 = LowLevelParticleFilters.MvNormal([x0; 2], R1)
discrete_dynamics = SeeToDee.Rk4(fdyn, 0.01)

ukf = UnscentedKalmanFilter(discrete_dynamics, g, R1, R2, d0; p, nu, ny)


@time filtersol = forward_trajectory(ukf, U, Y)
plot(filtersol, size=(1200, 1000), ploty=false, plotu=false)
X[end,:] .= 5.3
plot!(X', sp=(1:nx)', label=false, l=(:black, :dash))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions