Details

Details

ODE problem creation

Dynamics(mechanism)
Dynamics(mechanism, control!; setparams!)

Create a Dynamics object, representing either the passive or closed-loop dynamics of a RigidBodyDynamics.Mechanism.

The control! argument is a callable with the signature control!(τ, t, state), where τ is the torque vector to be set in the body of control!, t is the current time, and state is a MechanismState object. By default, control! is zero_control! (resulting in the passive dynamics).

The setparams! keyword argument is a callable with the signature setparams!(state, p) where state is a MechanismState and p is a vector of parameters, as used in OrdinaryDiffEq.jl.

source
ODEProblem(dynamics, x0, tspan)
ODEProblem(dynamics, x0, tspan, p; callback, kwargs...)

Create a DiffEqBase.ODEProblem associated with the dynamics of a RigidBodyDynamics.Mechanism.

The initial state x0 can be either a RigidBodyDynamics.MechanismState), or an AbstractVector containing the initial state represented as [q; v; s], where q is the configuration vector, v is the velocity vector, and s is the vector of additional states.

The callback keyword argument can be used to pass in additional DifferentialEquations.jl callbacks.

source

Control

zero_control!(τ, t, state)

A 'zero' controller, i.e. one that sets all control torques to zero at all times.

source
controlcallback(control!)

Can be used to create a callback associated with a given controller.

source
struct PeriodicController{Tau<:(AbstractArray{T,1} where T), T<:Number, C, I}

A PeriodicController can be used to simulate a digital controller that runs at a fixed rate (in terms of simulation time). It does so by performing a zero-order hold on a provided control function.

PeriodicControllers can be constructed using

PeriodicController(τ, Δt, control!; initialize = DiffEqBase.INITIALIZE_DEFAULT, save_positions = (false, false))

where control! is a controller satisfying the standard RigidBodySim controller signature (control!(τ, Δt, state)), Δt is the simulation time interval between calls to the control! function, and τ is used to call control!. The initialize and save_positions keyword arguments are documented in the DiscreteCallback section of the DifferentialEquations documentation.

PeriodicControllers are callable objects, and themselves fit the standard RigidBodySim controller signature.

A DiffEqCallbacks.PeriodicCallback can be created from a PeriodicController, and is used to stop ODE integration exactly every Δt seconds, so that the control! function can be called. Typically, users will not have to explicitly create this PeriodicCallback, as it is automatically created and added to the ODEProblem when the PeriodicController is passed into the RigidBodySim-provided DiffEqBase.ODEProblem constructor overload.

Examples

In the following example, a PeriodicController is used to simulate a digital PD controller running at a fixed rate of 200 Hz.

julia> using RigidBodySim, RigidBodyDynamics, OrdinaryDiffEq

julia> mechanism = parse_urdf(Float64, joinpath(dirname(pathof(RigidBodySim)), "..", "test", "urdf", "Acrobot.urdf"));

julia> state = MechanismState(mechanism);

julia> set_configuration!(state, [0.1; 0.2]);

julia> controlcalls = Ref(0);

julia> pdcontrol!(τ, t, state) = (controlcalls[] += 1; τ .= -20 .* velocity(state) .- 100 .* configuration(state));

julia> τ = zero(velocity(state)); Δt = 1 / 200
0.005

julia> problem = ODEProblem(Dynamics(mechanism, PeriodicController(τ, Δt, pdcontrol!)), state, (0., 5.));

julia> sol = solve(problem, Tsit5());

julia> @assert all(x -> isapprox(x, 0, atol = 1e-4), sol.u[end]) # ensure state converges to zero

julia> controlcalls[]
1001
source
struct SumController{Tau<:(AbstractArray{T,1} where T), C<:Tuple}

A SumController can be used to combine multiple controllers, summing the control torques that each of these controllers produces.

Examples

julia> using RigidBodySim, RigidBodyDynamics

julia> mechanism = parse_urdf(Float64, joinpath(dirname(pathof(RigidBodySim)), "..", "test", "urdf", "Acrobot.urdf"));

julia> state = MechanismState(mechanism);

julia> c1 = (τ, t, state) -> τ .= t;

julia> c2 = (τ, t, state) -> τ .= 2 * t;

julia> sumcontroller = SumController(similar(velocity(state)), (c1, c2))

julia> τ = similar(velocity(state))

julia> controller(τ, 1.0, state);

julia> @assert all(τ .== 3.0);
source

Visualization

RigidBodySim uses MeshCatMechanisms.jl for 3D visualization.

GUI(visualizer; usernode)

Create a new RigidBodySim graphical user interface given a visualizer (e.g. a MeshCatMechanisms.MechanismVisualizer).

The visualizer must support:

  • Base.copyto!(visualizer, state::Union{MechanismState, AbstractVector})
  • Base.wait(visualizer)
  • MeshCatMechanisms.visualizer(visualizer), which should return a MeshCat.Visualizer.

Use open(gui) to open the GUI in a standalone window.

source
GUI(mechanism, args; usernode)

Create a new RigidBodySim graphical user interface for the given Mechanism. All arguments are passed on to the MeshCatMechanisms.MechanismVisualizer constructor.

Use open(gui) to open the GUI in a standalone window.

source
SimulationControls()

Create a new SimulationControls object, which may be used to pause and terminate the simulation.

The controls can be displayed in a standalone window using open(controls, Blink.Window()).

source
CallbackSet(vis; max_fps)

Create the DifferentialEquations.jl callbacks needed for publishing to a visualizer during simulation.

max_fps is the maximum number of frames per second (in terms of wall time) to draw. Default: 60.0.

source
CallbackSet(gui; max_fps)

Create the DifferentialEquations.jl callbacks associated with the GUI.

max_fps is the maximum number of frames per second (in terms of wall time) to draw. Default: 60.0.

source
setanimation!(vis, sol; max_fps, realtime_rate, pause_pollint)

Play back a visualization of a RigidBodySim.jl simulation.

Positional arguments:

  • vis is a MeshCatMechanisms.MechanismVisualizer
  • sol is a DiffEqBase.ODESolution obtained from a RigidBodySim.jl simulation.

setanimation accepts the following keyword arguments:

  • max_fps: the maximum number of frames per second to draw. Default: 60.0.
  • realtime_rate: can be used to slow down or speed up playback compared to wall time. A realtime_rate of 2 will result in playback that is sped up 2x. Default: 1.0.

Examples

Visualizing the result of a simulation of the passive dynamics of an Acrobot (double pendulum) at half speed:

using RigidBodySim, RigidBodyDynamics, MeshCatMechanisms, Blink
urdf = joinpath(dirname(pathof(RigidBodySim)), "..", "test", "urdf", "Acrobot.urdf")
mechanism = parse_urdf(Float64, urdf)
state = MechanismState(mechanism)
set_configuration!(state, [0.1; 0.2])
problem = ODEProblem(Dynamics(mechanism), state, (0., 2.))
sol = solve(problem, Vern7())
vis = MechanismVisualizer(mechanism, URDFVisuals(urdf))
# open(vis, Window()) # uncomment to open the visualizer window
setanimation!(vis, sol; realtime_rate = 0.5);
source

Utilities

configuration_renormalizer(state)
configuration_renormalizer(state, condition)

configuration_renormalizer can be used to create a callback that projects the configuration of a mechanism's state onto the configuration manifold. This may be necessary for mechanism's with e.g. quaternion-parameterized orientations as part of their joint configuration vectors, as numerical integration can cause the configuration to drift away from the unit norm constraints.

The callback is implemented as a DiffEqCallbacks.DiscreteCallback By default, it is called at every integrator time step.

source
RealtimeRateLimiter(; max_rate, poll_interval, save_positions, reset_interval)
RealtimeRateLimiter(; max_rate = 1., poll_interval = 1 / 30; save_positions = (false, false))

A DiscreteCallback that limits the rate of integration so that integration time t increases at a rate no higher than max_rate compared to wall time.

A RealtimeRateLimiter can be used, for example, if you want to simulate a physical system including its timing characteristics. Specific use cases may include realtime animation and user interaction during the simulation.

The poll_interval keyword argument can be used to control how often the integration is stopped to check whether to sleep (and for how long). Specifically, this operation happens every poll_interval / max_rate in terms of integration time, which corresponds to approximately every poll_interval seconds wall time if max_rate is actually achieved.

source