Skip to content

Commit 7a4e658

Browse files
authored
Merge pull request #6 from JuliaRobotics/dev-0.3.x
TORA.jl v0.3
2 parents a08983c + 40d89c9 commit 7a4e658

File tree

13 files changed

+187
-79
lines changed

13 files changed

+187
-79
lines changed

.github/workflows/Documentation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- uses: actions/checkout@v2
1717
- uses: julia-actions/setup-julia@v1
1818
with:
19-
version: '1.6'
19+
version: '1.8'
2020
- name: Install dependencies
2121
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
2222
- name: Build and deploy

Project.toml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
name = "TORA"
22
uuid = "a6da6c0f-f153-4ec6-bf42-6dc0ab733f84"
33
authors = ["Henrique Ferrolho <[email protected]>"]
4-
version = "0.2.0"
4+
version = "0.3.0"
55

66
[deps]
77
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
88
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
99
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
10+
HSL_jll = "017b0a0e-03f4-516a-9b91-836bbd1904dd"
1011
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
1112
MeshCat = "283c5d60-a78f-5afe-a0af-af636b173e11"
1213
MeshCatMechanisms = "6ad125db-dd91-5488-b820-c1df6aab299d"
1314
NPZ = "15e1cf62-19b3-5cfa-8e77-841668bca605"
1415
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
1516
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
17+
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
1618
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1719
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
1820
RigidBodyDynamics = "366cf18f-59d5-5db9-a4de-86a9f6786172"
@@ -21,19 +23,20 @@ SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
2123
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2224

2325
[compat]
24-
Colors = "0.12"
26+
Colors = "0.12, 0.13"
2527
ForwardDiff = "0.10"
26-
GeometryBasics = "0.4"
28+
GeometryBasics = "0.4, 0.5"
2729
Ipopt = "1"
28-
MeshCat = "0.14"
29-
MeshCatMechanisms = "0.8"
30+
MeshCat = "0.14, 0.15, 0.16, 1"
31+
MeshCatMechanisms = "0.8, 0.9"
3032
NPZ = "0.4"
3133
Plots = "1"
34+
PrecompileTools = "1"
3235
Requires = "1"
3336
RigidBodyDynamics = "2"
34-
SparseDiffTools = "1"
37+
SparseDiffTools = "2"
3538
StaticArrays = "1"
36-
julia = "1.6"
39+
julia = "1.8"
3740

3841
[extras]
3942
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ using Documenter, TORA
55
makedocs(
66
modules = [TORA],
77
format = Documenter.HTML(),
8+
warnonly = Documenter.except(),
89
sitename = "TORA.jl",
910
authors = "Henrique Ferrolho",
1011
pages = [

notebooks/Example.ipynb

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
"metadata": {},
2828
"outputs": [],
2929
"source": [
30-
"# Workaround for: https://github.com/JuliaRobotics/RigidBodyDynamics.jl/issues/500\n",
31-
"using LinearAlgebra; BLAS.set_num_threads(1)"
30+
"using LinearAlgebra\n",
31+
"# Try to load something faster than OpenBLAS\n",
32+
"try using AppleAccelerate catch e; end\n",
33+
"try using MKL catch e; end\n",
34+
"BLAS.get_config()"
3235
]
3336
},
3437
{
@@ -37,11 +40,23 @@
3740
"metadata": {},
3841
"outputs": [],
3942
"source": [
40-
"using KNITRO\n",
43+
"# using KNITRO\n",
4144
"using MeshCat\n",
4245
"using RigidBodyDynamics"
4346
]
4447
},
48+
{
49+
"cell_type": "code",
50+
"execution_count": null,
51+
"metadata": {},
52+
"outputs": [],
53+
"source": [
54+
"# Load the pre-compiled binaries of Coin HSL routines\n",
55+
"HSL_jll_path = expanduser(\"~/HSL_jll.jl-2023.5.26\")\n",
56+
"Pkg.develop(path=HSL_jll_path)\n",
57+
"import HSL_jll"
58+
]
59+
},
4560
{
4661
"cell_type": "code",
4762
"execution_count": null,
@@ -71,8 +86,13 @@
7186
"metadata": {},
7287
"outputs": [],
7388
"source": [
74-
"robot = TORA.create_robot_kuka_iiwa_14(vis)\n",
75-
"problem = TORA.Problem(robot, 301, 1/150)\n",
89+
"robot = TORA.create_robot_franka(\"panda_arm\", vis)\n",
90+
"# robot = TORA.create_robot_kinova_gen2(\"j2s6s200\", vis)\n",
91+
"# robot = TORA.create_robot_kinova_gen3(\"gen3_robotiq_2f_140\", vis)\n",
92+
"# robot = TORA.create_robot_kuka(\"iiwa14\", vis)\n",
93+
"# robot = TORA.create_robot_ur(\"ur10e\", vis)\n",
94+
"\n",
95+
"problem = TORA.Problem(robot, 2001, 1/1000)\n",
7696
"\n",
7797
"# Constrain initial and final joint velocities to zero\n",
7898
"TORA.fix_joint_velocities!(problem, robot, 1, zeros(robot.n_v))\n",
@@ -90,7 +110,8 @@
90110
"\n",
91111
" for k = 1:2:problem.num_knots\n",
92112
" θ = CubicTimeScaling(problem.num_knots - 1, k - 1) * 2π\n",
93-
" pos = [0.5, 0.2 * cos(θ), 0.8 + 0.2 * sin(θ)]\n",
113+
" # pos = [0.5, 0.2 * cos(θ), 0.8 + 0.2 * sin(θ)] # UR10e\n",
114+
" pos = [0.4, 0.2 * cos(θ), 0.7 + 0.2 * sin(θ)] # Franka Emika\n",
94115
" # pos = [0.5, 0.3 * sin(θ) + 0.1 * sin(8 * θ), 0.8 + 0.3 * cos(θ) + 0.1 * cos(8 * θ)]\n",
95116
" TORA.constrain_ee_position!(problem, k, pos)\n",
96117
" end\n",
@@ -105,7 +126,11 @@
105126
"metadata": {},
106127
"outputs": [],
107128
"source": [
108-
"initial_q = [0, 0, 0, -π/2, 0, 0, 0]\n",
129+
"initial_q = zeros(robot.n_q)\n",
130+
"# initial_q = [0, 0, 0, -π/2, 0, 0, 0]\n",
131+
"initial_q = [0, -π/4, 0, -3π/4, 0, π/2, 0] # Franka Emika\n",
132+
"# initial_q = [0, -120, 120, -180, -90, 0] .|> deg2rad # UR10e\n",
133+
"# initial_q = x[1:7]\n",
109134
"\n",
110135
"zero!(robot.state)\n",
111136
"set_configuration!(robot.state, initial_q)\n",
@@ -130,6 +155,45 @@
130155
"use_inv_dyn = true\n",
131156
"minimise_τ = false\n",
132157
"\n",
158+
"user_options = Dict(\n",
159+
" # === Termination === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Termination\n",
160+
" # \"tol\" => 10e-2, # default: 10e-8\n",
161+
" # \"max_cpu_time\" => 4.0, # default: 10e20\n",
162+
" # \"constr_viol_tol\" => 0.1, # default: 0.0001\n",
163+
" # \"acceptable_tol\" => 0.1, # default: 10e-6\n",
164+
" # \"acceptable_constr_viol_tol\" => 0.1, # default: 0.01\n",
165+
"\n",
166+
" # === Output === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Output\n",
167+
" # \"print_level\" => 0, # [0, 12], default: 5\n",
168+
" \n",
169+
" # === NLP Scaling === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_NLP_Scaling\n",
170+
" # \"nlp_scaling_method\" => \"none\", # none, user-scaling, gradient-based (default), equilibration-based\n",
171+
"\n",
172+
" # === Warm Start === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Warm_Start\n",
173+
" # \"warm_start_init_point\" => \"yes\",\n",
174+
" # \"warm_start_same_structure\" => \"yes\",\n",
175+
" # \"warm_start_entire_iterate\" => \"yes\",\n",
176+
"\n",
177+
" # === Barrier Parameter Update === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Barrier_Parameter_Update\n",
178+
" \"mu_strategy\" => \"adaptive\", # monotone (default), adaptive\n",
179+
" # \"mu_oracle\" => \"loqo\", # probing, loqo, quality-function (default)\n",
180+
"\n",
181+
" # === Linear Solver === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Linear_Solver\n",
182+
" \"linear_solver\" => \"ma57\", # ma27 (default), ma57, ma77, ma86, ma97, (...)\n",
183+
" # \"ma57_pre_alloc\" => 1.10, # [1, Inf), 1.05 (default)\n",
184+
"\n",
185+
" # === Step Calculation === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Step_Calculation\n",
186+
" # \"mehrotra_algorithm\" => \"yes\", # yes, no (default)\n",
187+
" \"fast_step_computation\" => \"yes\", # yes, no (default)\n",
188+
"\n",
189+
" # === Hessian Approximation === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Hessian_Approximation\n",
190+
" \"hessian_approximation\" => \"limited-memory\", # exact (default), limited-memory\n",
191+
" # \"hessian_approximation_space\" => \"all-variables\", # nonlinear-variables (default), all-variables\n",
192+
"\n",
193+
" # === Derivative Checker === # https://coin-or.github.io/Ipopt/OPTIONS.html#OPT_Derivative_Checker\n",
194+
" # \"derivative_test\" => \"first-order\", # none, first-order, second-order, only-second-order\n",
195+
")\n",
196+
"\n",
133197
"# Choose which solver you want to use:\n",
134198
"solve = TORA.solve_with_ipopt # Uses Ipopt (https://github.com/coin-or/Ipopt)\n",
135199
"# solve = TORA.solve_with_knitro # Uses KNITRO (https://www.artelys.com/solvers/knitro/)\n",
@@ -138,7 +202,8 @@
138202
"cpu_time, x, solver_log = solve(problem, robot,\n",
139203
" initial_guess=initial_guess,\n",
140204
" use_inv_dyn=use_inv_dyn,\n",
141-
" minimise_τ=minimise_τ)"
205+
" minimise_τ=minimise_τ,\n",
206+
" user_options=user_options)"
142207
]
143208
},
144209
{
@@ -162,7 +227,9 @@
162227
{
163228
"cell_type": "code",
164229
"execution_count": null,
165-
"metadata": {},
230+
"metadata": {
231+
"tags": []
232+
},
166233
"outputs": [],
167234
"source": [
168235
"TORA.plot_log(solver_log)"
@@ -171,15 +238,15 @@
171238
],
172239
"metadata": {
173240
"kernelspec": {
174-
"display_name": "Julia 1.7.2",
241+
"display_name": "Julia 1.10.2",
175242
"language": "julia",
176-
"name": "julia-1.7"
243+
"name": "julia-1.10"
177244
},
178245
"language_info": {
179246
"file_extension": ".jl",
180247
"mimetype": "application/julia",
181248
"name": "julia",
182-
"version": "1.7.2"
249+
"version": "1.10.2"
183250
}
184251
},
185252
"nbformat": 4,

notebooks/Tutorial.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,15 @@
128128
],
129129
"metadata": {
130130
"kernelspec": {
131-
"display_name": "Julia 1.7.2",
131+
"display_name": "Julia 1.10.2",
132132
"language": "julia",
133-
"name": "julia-1.7"
133+
"name": "julia-1.10"
134134
},
135135
"language_info": {
136136
"file_extension": ".jl",
137137
"mimetype": "application/julia",
138138
"name": "julia",
139-
"version": "1.7.2"
139+
"version": "1.10.2"
140140
}
141141
},
142142
"nbformat": 4,

src/TORA.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ include("./constraints/end_effector.jl")
6161
include("./transcription/ipopt.jl")
6262
include("./plots.jl")
6363

64+
# Code to "exercise" the package - see https://julialang.github.io/PrecompileTools.jl/stable/
65+
include("./precompile.jl")
66+
6467
export solve_with_knitro
6568

6669
end # module

src/constraints/dynamics.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ function make_cb_eval_ga_con_dyn(problem, robot, jacdata)
125125
jacdata(x[ind_vars])
126126

127127
# Pass the Jacobian to Knitro
128-
offset_jac = i * jacdata.length_jac
129-
ind_jac = (1:jacdata.length_jac) .+ offset_jac
128+
offset_jac = i * jacdata.jac_length
129+
ind_jac = (1:jacdata.jac_length) .+ offset_jac
130130
evalResult.jac[ind_jac] = nonzeros(jacdata.jac)
131131
end
132132

src/constraints/end_effector.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function cb_eval_ga_con_ee(kc, cb, evalRequest, evalResult, userParams)
3434
for (i, k) = enumerate(sort(collect(keys(problem.ee_pos))))
3535
ind_qᵢ = range(1 + (k - 1) * nₓ, length=robot.n_q) # indices of the decision variables
3636
problem.jacdata_ee_position(x[ind_qᵢ]) # jacobian evaluation at that point
37-
ind_jac = (1:problem.jacdata_ee_position.length_jac) .+ ((i - 1) * problem.jacdata_ee_position.length_jac)
37+
ind_jac = (1:problem.jacdata_ee_position.jac_length) .+ ((i - 1) * problem.jacdata_ee_position.jac_length)
3838
evalResult.jac[ind_jac] = nonzeros(problem.jacdata_ee_position.jac) # pass jacobian to Knitro
3939
end
4040

src/jacobian_data.jl

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,59 @@
1-
struct JacobianData{T1 <: SparseMatrixCSC,T2 <: ForwardColorJacCache}
2-
f!::Function
3-
jac::T1
4-
jac_cache::T2
5-
length_jac::Int
6-
sparsity::SparseArrays.SparseMatrixCSC{Bool,Int64}
7-
8-
function JacobianData(f!, output, input)
9-
# TODO Proper way to do it (currently not working)
10-
# Issue: https://github.com/SciML/SparsityDetection.jl/issues/41
11-
# sparsity = jacobian_sparsity(f!, output, input)
12-
13-
# Workaround
1+
import SparseArrays
2+
import SparseDiffTools
3+
# import Symbolics
4+
5+
"""
6+
`JacobianData` is a utility strcture to hold Jacobian information associated with a given function.
7+
"""
8+
struct JacobianData{T,F<:Function,C<:SparseDiffTools.ForwardColorJacCache}
9+
f!::F
10+
jac::SparseArrays.SparseMatrixCSC{T,Int}
11+
jac_cache::C
12+
jac_length::Int
13+
jac_sparsity::SparseArrays.SparseMatrixCSC{Bool,Int}
14+
15+
@doc """
16+
JacobianData(f!, output, input)
17+
18+
Create a new `JacobianData`.
19+
20+
# Arguments
21+
- `f!`: the method associated with this `JacobianData`
22+
- `output`: input vector to be passed to `f!`
23+
- `input`: output vector expected from `f!`
24+
"""
25+
function JacobianData(f!::F, output::Vector{T}, input::Vector{T}) where {T,F<:Function}
26+
# # Issue: https://github.com/SciML/SparsityDetection.jl/issues/41
27+
# # Calculate the sparsity pattern of the Jacobian
28+
# jac_sparsity = Symbolics.jacobian_sparsity(f!, output, input)
29+
30+
# [HACKY!] Calculate the sparsity pattern of the Jacobian
1431
num_samples = 50
1532
jac_samples = [ForwardDiff.jacobian(f!, rand!(output), rand!(input)) for _ in 1:num_samples]
16-
sparsity = sparse(sum(jac_samples) .≠ 0)
33+
jac_sparsity = SparseArrays.sparse(sum(jac_samples) .≠ 0)
1734

18-
jac = convert.(Float64, sparse(sparsity))
35+
# Placeholder for the actual Jacobian
36+
jac = T.(jac_sparsity)
1937

20-
jac_cache = ForwardColorJacCache(f!, input, dx=output,
21-
colorvec=matrix_colors(jac),
22-
sparsity=sparsity)
38+
# Color the sparse matrix using graphical techniques (colorvec-assisted differentiation is significantly faster)
39+
colorvec = SparseDiffTools.matrix_colors(jac)
2340

24-
length_jac = nnz(jac)
41+
# Construct the color cache in advance, in order to not compute it each time the Jacobian needs to be evaluated
42+
jac_cache = SparseDiffTools.ForwardColorJacCache(f!, input, dx=output, colorvec=colorvec, sparsity=jac_sparsity)
2543

26-
T1 = typeof(jac)
27-
T2 = typeof(jac_cache)
44+
# The length of the Jacobian, i.e., the number of non-zero elements
45+
jac_length = SparseArrays.nnz(jac)
2846

29-
new{T1,T2}(f!, jac, jac_cache, length_jac, sparsity)
47+
C = typeof(jac_cache)
48+
49+
new{T,F,C}(f!, jac, jac_cache, jac_length, jac_sparsity)
3050
end
3151
end
3252

33-
function (jd::JacobianData)(x)
34-
forwarddiff_color_jacobian!(jd.jac, jd.f!, x, jd.jac_cache)
35-
end
53+
"""
54+
Evaluate this `JacobianData`'s function `f!` for point `x` using forward-mode automatic differentiation.
55+
56+
This method's syntax is "special". For more info on Function-like-objects, read the
57+
[docs](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects).
58+
"""
59+
(jd::JacobianData)(x) = SparseDiffTools.forwarddiff_color_jacobian!(jd.jac, jd.f!, x, jd.jac_cache)

src/precompile.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import PrecompileTools
2+
3+
PrecompileTools.@compile_workload begin
4+
vis = Visualizer()
5+
robot = create_robot_franka("panda_arm", vis)
6+
problem = Problem(robot, 201, 1/100)
7+
fix_joint_velocities!(problem, robot, 1, zeros(robot.n_v))
8+
cpu_time, x, solver_log = solve_with_ipopt(problem, robot)
9+
play_trajectory(vis, problem, robot, x)
10+
plot_results(problem, robot, x)
11+
Plots.closeall()
12+
MeshCat.close_server!(vis.core)
13+
end

0 commit comments

Comments
 (0)