using RigidBodyDynamics
using LinearAlgebra
using StaticArrays
using RigidBodyDynamics.OdeIntegrators: step, process
using RigidBodyDynamics.OdeIntegrators
using Zygote;
free floting object
function init_RigidBody()
world_body = RigidBody{Float64}("world");
rigid_body_mechanism = Mechanism(world_body; gravity = SVector(0, 0, -9.81));
# Body
frame = CartesianFrame3D("frame"); # the reference frame in which the spatial inertia will be expressed
inertia = SpatialInertia( frame,
moment = Matrix(0.01I, 3, 3), # moment of inertia,
com = SVector(0, 0, 0), # center of mass location with respect to joint axis
mass = 1.0);
body = RigidBody(inertia)
# The joint is used by the sim_callback! therefore it must be available globally.
global joint = Joint("joint", QuaternionFloating{Float64}());
to_world = one(Transform3D, frame_before(joint), default_frame(world_body))
attach!(rigid_body_mechanism, world_body, body, joint, joint_pose = to_world);
mechanism_state = MechanismState(rigid_body_mechanism);
# Set the initial mechanism_state configuration
set_configuration!(mechanism_state, joint, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # in World Frame
set_velocity!(mechanism_state, joint, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # In Body frame
return mechanism_state, joint
end;
function sim_callback!(torques::AbstractVector{T}, t, state::MechanismState{T}) where T
# takes the Global Torque, Force and Joint Value
torques[velocity_range(state, joint)] = [torque_B; force_B]
end;
function init_integrator(mechanism_state)
T = Float64;
result = DynamicsResult{T}(mechanism_state.mechanism)
control_torques::AbstractVector{T} = [0.0; 0.0; 0.0; 0.0; 0.0; 0.0];
#a callable dynamics!(vd, t, state) that updates the joint acceleration vector vd at time t and in state state;
closed_loop_dynamics! = function (v̇::AbstractArray, ṡ::AbstractArray, t, state)
sim_callback!(control_torques, t, state)
dynamics!(result, state, control_torques)
copyto!(v̇, result.v̇)
copyto!(ṡ, result.ṡ)
end
tableau = runge_kutta_4(T) # Return the Butcher tableau for the standard fourth order Runge-Kutta integrator.
storage = RingBufferStorage{T}(mechanism_state, 1); # Ringbuffer with one place as OdeResultsSink
integrator = MuntheKaasIntegrator(mechanism_state, closed_loop_dynamics!, tableau, storage);
return integrator, storage
end;
function rigid_body_simulation_step(integrator, t, Δt, storage)
step(integrator, t, Δt)
# Returns the position of the body
x_W = configuration(integrator.state)[7]
return x_W
end;
function set_next_torque_force!(torque_B_::AbstractVector{T}, force_B_::AbstractVector{T}) where T
# Since the MuntheKaasIntegrator calls the dynamic update, the new force values must be passed globally.
global torque_B = torque_B_;
global force_B = force_B_;
end;
The function initialises the rigid body simulation and simulates 10 time steps for a free flying body. The loss is the deviation from the origin. x is the force acting on the cube against gravity.
function f(x)
t = 0.0;
Δt = 1e-2;
loss = 0.0;
# The force acting on the body along the gravity can be varied by x.
force_B = [0.0; 0.0; x];
torque_B = [0.0; 0.0; 0.0];
for i in 1:10
set_next_torque_force!(torque_B, force_B)
x_W = rigid_body_simulation_step(integrator, t, Δt, storage)
loss += norm(x_W)
t = Δt;
end
# The loss is the sum of all positions deviating from the origin.
return loss
end;
mechanism_state, joint = init_RigidBody();
integrator, storage = init_integrator(mechanism_state);
Test whether the movement is 0 when a force equal to gravity acts in the opposite direction.
0.0 == f(9.81)
true
x = 0.0
gradient(f, x)
Mutating arrays is not supported -- called copyto!(::Vector{Float64}, _...) Stacktrace: [1] error(s::String) @ Base ./error.jl:33 [2] (::Zygote.var"#445#446"{Vector{Float64}})(#unused#::Nothing) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/lib/array.jl:74 [3] (::Zygote.var"#2347#back#447"{Zygote.var"#445#446"{Vector{Float64}}})(Δ::Nothing) @ Zygote ~/.julia/packages/ZygoteRules/AIbCs/src/adjoint.jl:67 [4] Pullback @ ~/.julia/packages/RigidBodyDynamics/8B04X/src/mechanism_state.jl:441 [inlined] [5] (::typeof(∂(set_additional_state!)))(Δ::Nothing) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface2.jl:0 [6] Pullback @ ~/.julia/packages/RigidBodyDynamics/8B04X/src/ode_integrators.jl:296 [inlined] [7] (::typeof(∂(step)))(Δ::Nothing) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface2.jl:0 [8] Pullback @ ./In[5]:2 [inlined] [9] (::typeof(∂(rigid_body_simulation_step)))(Δ::Float64) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface2.jl:0 [10] Pullback @ ./In[7]:13 [inlined] [11] (::typeof(∂(f)))(Δ::Float64) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface2.jl:0 [12] (::Zygote.var"#56#57"{typeof(∂(f))})(Δ::Float64) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface.jl:41 [13] gradient(f::Function, args::Float64) @ Zygote ~/.julia/packages/Zygote/Y6SC4/src/compiler/interface.jl:76 [14] top-level scope @ In[10]:2 [15] eval @ ./boot.jl:373 [inlined] [16] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1196