-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Reenable all notebook tests now that required packages all support Julia 1.0. * Put each notebook in a separate directory, with its own Project.toml and Manifest.toml, to make running the notebooks more straightforward (see JuliaLang/IJulia.jl#673). * Separate Project.toml and Manifest.toml files for optional visualization parts of the notebooks (not tested by CI, since this would introduce a cyclic test dependency). * Fix #501, Symbolic Double Pendulum not working (work around JuliaPy/SymPy.jl#245 and JuliaPy/SymPy.jl#244).
- Loading branch information
Showing
32 changed files
with
4,106 additions
and
1,756 deletions.
There are no files selected for viewing
265 changes: 265 additions & 0 deletions
265
...s/Closed-loop simulation and visualization/Closed-loop simulation and visualization.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Setup" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m registry at `~/.julia/registries/General`\n", | ||
"\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m git-repo `https://github.com/JuliaRegistries/General.git`\n", | ||
"\u001b[?25l\u001b[2K\u001b[?25h\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m project...\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"using Pkg\n", | ||
"Pkg.activate(@__DIR__);\n", | ||
"pkg\"instantiate\"\n", | ||
"pkg\"precompile\"" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"using RigidBodyDynamics" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Please note that [RigidBodySim.jl](https://github.com/JuliaRobotics/RigidBodySim.jl) now provides a more capable simulation environment." | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Model definition" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We'll just use the double pendulum model, loaded from a URDF:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"Spanning tree:\n", | ||
"Vertex: world (root)\n", | ||
" Vertex: upper_link, Edge: shoulder\n", | ||
" Vertex: lower_link, Edge: elbow\n", | ||
"No non-tree joints." | ||
] | ||
}, | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"urdf = joinpath(dirname(pathof(RigidBodyDynamics)), \"..\", \"test\", \"urdf\", \"Acrobot.urdf\")\n", | ||
"mechanism = parse_urdf(urdf)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Controller" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Let's write a simple controller that just applies $10 \\sin(t)$ at the elbow joint and adds some damping at the shoulder joint:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"simple_control! (generic function with 1 method)" | ||
] | ||
}, | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"shoulder, elbow = joints(mechanism)\n", | ||
"function simple_control!(torques::AbstractVector, t, state::MechanismState)\n", | ||
" torques[velocity_range(state, shoulder)] .= -1 .* velocity(state, shoulder)\n", | ||
" torques[velocity_range(state, elbow)] .= 10 * sin(t)\n", | ||
"end" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Simulation" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Basic simulation can be done using the `simulate` function. We'll first create a `MechanismState` object, and set the initial joint configurations and velocities:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"state = MechanismState(mechanism)\n", | ||
"zero_velocity!(state)\n", | ||
"set_configuration!(state, shoulder, 0.7)\n", | ||
"set_configuration!(state, elbow, -0.8);" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Now we can simply call `simulate`, which will return a tuple consisting of:\n", | ||
"* simulation times (a `Vector` of numbers)\n", | ||
"* joint configuration vectors (a `Vector` of `Vector`s)\n", | ||
"* joint velocity vectors (a `Vector` of `Vector`s)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"final_time = 10.\n", | ||
"ts, qs, vs = simulate(state, final_time, simple_control!; Δt = 1e-3);" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"For access to lower-level functionality, such as different ways of storing or visualizing the data generated during the simulation, it is advised to simply pattern match the basic `simulate` function." | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Visualization" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"For visualization, we'll use [`MeshCatMechanisms`](https://github.com/JuliaRobotics/MeshCatMechanisms.jl), an external package based on RigidBodyDynamics.jl.\n", | ||
"\n", | ||
"(Note: the `#NBSKIP` comments are to skip these cells during `Pkg.test(\"RigidBodyDynamics\")`)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"#NBSKIP\n", | ||
"Pkg.activate(joinpath(@__DIR__, \"visualization\"));\n", | ||
"pkg\"instantiate\"\n", | ||
"pkg\"precompile\"\n", | ||
"using MeshCatMechanisms" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Create a `MechanismVisualizer` and open it in a new browser tab (see [`MeshCat.jl`](https://github.com/rdeits/MeshCat.jl) for other options):" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"#NBSKIP\n", | ||
"mvis = MechanismVisualizer(mechanism, URDFVisuals(urdf))\n", | ||
"open(mvis);" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"And animate:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"#NBSKIP\n", | ||
"MeshCatMechanisms.animate(mvis, ts, qs; realtimerate = 1.);" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Julia 1.0.0", | ||
"language": "julia", | ||
"name": "julia-1.0" | ||
}, | ||
"language_info": { | ||
"file_extension": ".jl", | ||
"mimetype": "application/julia", | ||
"name": "julia", | ||
"version": "1.0.0" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
Oops, something went wrong.