Assigning a user-defined function to RobotDynamics.dynamics()

Hi,

I am using the RobotDynamics Julia interface to define an optimal control problem, specifically, I would like to dynamically create a function that matches the style of function that RobotDynamics.dynamics() supports.

Basically it means instead of defining the function directly in the file as below,

function RobotDynamics.dynamics!(model::MyModel, x, u)
    ẋ = [u[1], x[1] + u[1]]
    return  ẋ
end

I have customized a similar function and stored it into the field “dynamics” in the struct below.

mutable struct Optimizer
    ...
    dynamics::Function
    ...
end

RobotDynamics.dynamics!(model::user_problem, x, u) = opt.dynamics

The problem is, during the optimization process, it seems that Julia incorrectly recognized my function as a type so the multiplication cannot be done, shown in the error report below. I am not sure why this is the case, so I am not sure if my method is actually doable or not.

As for the extra argument “t”, I think it is automatically transformed in the bottom code.

#in RobotDynamics\src\integration.jl
function integrate(::RK4, model, x, u, t, h)
    k1 = dynamics(model, x, u, t) * h         #line 281
    k2 = dynamics(model, x + k1 / 2, u, t + h / 2) * h
    k3 = dynamics(model, x + k2 / 2, u, t + h / 2) * h
    k4 = dynamics(model, x + k3, u, t + h) * h
    x + (k1 + 2k2 + 2k3 + k4) / 6
end

MethodError: no method matching *(::typeof(My_repository_name.my_function_name), ::Float64)
at line 281
#in RobotDynamics.jl/src/dynamics.jl line 83
@inline dynamics(model::ContinuousDynamics, x, u, t) = dynamics(model, x, u)

Any suggestion on the source of the problem would help, thank you.

This line

returns an unevaluated function that is independent of the arguments. You need to call opt.dynamics when implementing RobotDynamics.dynamics!.

Try this, then you don’t need the extra function to remove the time argument.

RobotDynamics.dynamics!(model::user_problem, x, u, t) = opt.dynamics(model, x, u)

I’m a little worried about capturing opt in the closure if you need high performance, but without seeing more of your code I can’t suggest a better alternative.

2 Likes

Thank you, it is working now, though I am not sure why the original method returns a function that is unevaluated and how adding the argument list corrects it.

Another way to write these two lines is

# Equivalent to
# RobotDynamics.dynamics!(model::user_problem, x, u) = opt.dynamics
function RobotDynamics.dynamics!(model::user_problem, x, u)
    return opt.dynamics
end

Which returns the value opt.dynamics

and

# Equivalent to
# RobotDynamics.dynamics!(model::user_problem, x, u, t) = opt.dynamics(model, x, u)
function RobotDynamics.dynamics!(model::user_problem, x, u, t)
    return opt.dynamics(model, x, u)
end

Which returns the result of calling the function opt.dynamics with the provided arguments.

1 Like