├── .gitignore ├── .gitmodules ├── README.md ├── examples ├── Manifest.toml ├── Project.toml ├── interactive_cartpole_ext.ipynb ├── interactive_quadrotor_ext.ipynb ├── interactive_safety_filter.ipynb └── visualization.jl └── tinympc ├── Project.toml └── TinyMPC.jl /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | generated_code*/ 3 | *.mp4 4 | examples/*.h 5 | 6 | /*.tar.gz 7 | /tmp 8 | /dist 9 | /dist-extras 10 | /julia 11 | /julia.bat 12 | /usr 13 | /oprofile_data 14 | /usr-staging 15 | /Make.user 16 | /julia-* 17 | /source-dist.tmp 18 | /source-dist.tmp1 19 | 20 | *.expmap 21 | *.exe 22 | *.dll 23 | *.dwo 24 | *.do 25 | *.o 26 | *.o.tmp 27 | *.obj 28 | *.so 29 | *.dylib 30 | *.dSYM 31 | *.h.gen 32 | *.jl.cov 33 | *.jl.*.cov 34 | *.jl.mem 35 | *.jl.*.mem 36 | *.ji 37 | 38 | /perf* 39 | .DS_Store 40 | .idea/* 41 | .vscode/* 42 | *.heapsnapshot 43 | .cache 44 | # Buildkite: Ignore the entire .buildkite directory 45 | /.buildkite 46 | 47 | # Buildkite: Ignore the unencrypted repo_key 48 | repo_key 49 | 50 | # Buildkite: Ignore any agent keys (public or private) we have stored 51 | agent_key* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tinympc/TinyMPC"] 2 | path = tinympc/TinyMPC 3 | url = https://github.com/TinyMPC/TinyMPC.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Julia interactive interface for TinyMPC 2 | 3 | Julia wrapper for [TinyMPC](https://tinympc.org/). It supports code generation and interaction with the C/C++ code. 4 | 5 | ## Installation 6 | 7 | 1. Clone this repo with submodule 8 | 9 | ```bash 10 | git clone --recurse-submodules https://github.com/TinyMPC/tinympc-julia.git 11 | ``` 12 | 13 | 2. Run the interactive example `interactive_cartpole_ext.ipynb` 14 | 15 | ## Documentation 16 | 17 | The interface is documented [here](https://tinympc.org/). 18 | 19 | ## Packaging 20 | -------------------------------------------------------------------------------- /examples/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | [[Adapt]] 4 | deps = ["LinearAlgebra", "Requires"] 5 | git-tree-sha1 = "0fb305e0253fd4e833d486914367a2ee2c2e78d0" 6 | uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" 7 | version = "4.0.1" 8 | 9 | [[ArgTools]] 10 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 11 | 12 | [[Artifacts]] 13 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 14 | 15 | [[Base64]] 16 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 17 | 18 | [[BitFlags]] 19 | git-tree-sha1 = "2dc09997850d68179b69dafb58ae806167a32b1b" 20 | uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" 21 | version = "0.1.8" 22 | 23 | [[BlockDiagonals]] 24 | deps = ["ChainRulesCore", "FillArrays", "FiniteDifferences", "LinearAlgebra"] 25 | git-tree-sha1 = "920d3775e35c519a2aced9e7bbe9ac61218eeead" 26 | uuid = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0" 27 | version = "0.1.42" 28 | 29 | [[Bzip2_jll]] 30 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 31 | git-tree-sha1 = "9e2a6b69137e6969bab0152632dcb3bc108c8bdd" 32 | uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" 33 | version = "1.0.8+1" 34 | 35 | [[Cairo_jll]] 36 | deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] 37 | git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" 38 | uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" 39 | version = "1.16.1+1" 40 | 41 | [[Cassette]] 42 | git-tree-sha1 = "0970356c3bb9113309c74c27c87083cf9c73880a" 43 | uuid = "7057c7e9-c182-5462-911a-8362d720325c" 44 | version = "0.3.13" 45 | 46 | [[ChainRulesCore]] 47 | deps = ["Compat", "LinearAlgebra", "SparseArrays"] 48 | git-tree-sha1 = "0d12ee16b3f62e4e33c3277773730a5b21a74152" 49 | uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" 50 | version = "1.20.0" 51 | 52 | [[ChangesOfVariables]] 53 | deps = ["InverseFunctions", "LinearAlgebra", "Test"] 54 | git-tree-sha1 = "2fba81a302a7be671aefe194f0525ef231104e7f" 55 | uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" 56 | version = "0.1.8" 57 | 58 | [[CodecZlib]] 59 | deps = ["TranscodingStreams", "Zlib_jll"] 60 | git-tree-sha1 = "cd67fc487743b2f0fd4380d4cbd3a24660d0eec8" 61 | uuid = "944b1d66-785c-5afd-91f1-9de20f533193" 62 | version = "0.7.3" 63 | 64 | [[ColorSchemes]] 65 | deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] 66 | git-tree-sha1 = "67c1f244b991cad9b0aa4b7540fb758c2488b129" 67 | uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" 68 | version = "3.24.0" 69 | 70 | [[ColorTypes]] 71 | deps = ["FixedPointNumbers", "Random"] 72 | git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" 73 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 74 | version = "0.11.4" 75 | 76 | [[ColorVectorSpace]] 77 | deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] 78 | git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249" 79 | uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" 80 | version = "0.10.0" 81 | 82 | [[Colors]] 83 | deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] 84 | git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a" 85 | uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" 86 | version = "0.12.10" 87 | 88 | [[CommonSubexpressions]] 89 | deps = ["MacroTools", "Test"] 90 | git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" 91 | uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" 92 | version = "0.3.0" 93 | 94 | [[Compat]] 95 | deps = ["Dates", "LinearAlgebra", "TOML", "UUIDs"] 96 | git-tree-sha1 = "75bd5b6fc5089df449b5d35fa501c846c9b6549b" 97 | uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" 98 | version = "4.12.0" 99 | 100 | [[CompilerSupportLibraries_jll]] 101 | deps = ["Artifacts", "Libdl"] 102 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 103 | 104 | [[ConcurrentUtilities]] 105 | deps = ["Serialization", "Sockets"] 106 | git-tree-sha1 = "8cfa272e8bdedfa88b6aefbbca7c19f1befac519" 107 | uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" 108 | version = "2.3.0" 109 | 110 | [[ConstructionBase]] 111 | deps = ["LinearAlgebra"] 112 | git-tree-sha1 = "c53fc348ca4d40d7b371e71fd52251839080cbc9" 113 | uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" 114 | version = "1.5.4" 115 | 116 | [[Contour]] 117 | git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" 118 | uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" 119 | version = "0.6.2" 120 | 121 | [[CoordinateTransformations]] 122 | deps = ["LinearAlgebra", "StaticArrays"] 123 | git-tree-sha1 = "f9d7112bfff8a19a3a4ea4e03a8e6a91fe8456bf" 124 | uuid = "150eb455-5306-5404-9cee-2592286d6298" 125 | version = "0.6.3" 126 | 127 | [[DataAPI]] 128 | git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" 129 | uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" 130 | version = "1.16.0" 131 | 132 | [[DataStructures]] 133 | deps = ["Compat", "InteractiveUtils", "OrderedCollections"] 134 | git-tree-sha1 = "ac67408d9ddf207de5cfa9a97e114352430f01ed" 135 | uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 136 | version = "0.18.16" 137 | 138 | [[DataValueInterfaces]] 139 | git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" 140 | uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" 141 | version = "1.0.0" 142 | 143 | [[Dates]] 144 | deps = ["Printf"] 145 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 146 | 147 | [[DelimitedFiles]] 148 | deps = ["Mmap"] 149 | uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" 150 | 151 | [[DiffResults]] 152 | deps = ["StaticArraysCore"] 153 | git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" 154 | uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" 155 | version = "1.1.0" 156 | 157 | [[DiffRules]] 158 | deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] 159 | git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" 160 | uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" 161 | version = "1.15.1" 162 | 163 | [[DocStringExtensions]] 164 | deps = ["LibGit2"] 165 | git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" 166 | uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 167 | version = "0.9.3" 168 | 169 | [[Downloads]] 170 | deps = ["ArgTools", "LibCURL", "NetworkOptions"] 171 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 172 | 173 | [[EarCut_jll]] 174 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 175 | git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" 176 | uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" 177 | version = "2.2.4+0" 178 | 179 | [[EpollShim_jll]] 180 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 181 | git-tree-sha1 = "8e9441ee83492030ace98f9789a654a6d0b1f643" 182 | uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43" 183 | version = "0.0.20230411+0" 184 | 185 | [[ExceptionUnwrapping]] 186 | deps = ["Test"] 187 | git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a" 188 | uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" 189 | version = "0.1.10" 190 | 191 | [[Expat_jll]] 192 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 193 | git-tree-sha1 = "4558ab818dcceaab612d1bb8c19cee87eda2b83c" 194 | uuid = "2e619515-83b5-522b-bb60-26c02a35a201" 195 | version = "2.5.0+0" 196 | 197 | [[Extents]] 198 | git-tree-sha1 = "2140cd04483da90b2da7f99b2add0750504fc39c" 199 | uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" 200 | version = "0.1.2" 201 | 202 | [[FFMPEG]] 203 | deps = ["FFMPEG_jll"] 204 | git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" 205 | uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" 206 | version = "0.4.1" 207 | 208 | [[FFMPEG_jll]] 209 | deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] 210 | git-tree-sha1 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e" 211 | uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" 212 | version = "4.4.4+1" 213 | 214 | [[FillArrays]] 215 | deps = ["LinearAlgebra", "PDMats", "Random", "SparseArrays", "Statistics"] 216 | git-tree-sha1 = "5b93957f6dcd33fc343044af3d48c215be2562f1" 217 | uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" 218 | version = "1.9.3" 219 | 220 | [[FiniteDifferences]] 221 | deps = ["ChainRulesCore", "LinearAlgebra", "Printf", "Random", "Richardson", "SparseArrays", "StaticArrays"] 222 | git-tree-sha1 = "d77e4697046989f44dce3ed66269aaf1611a3406" 223 | uuid = "26cc04aa-876d-5657-8c51-4c34ba976000" 224 | version = "0.12.31" 225 | 226 | [[FixedPointNumbers]] 227 | deps = ["Statistics"] 228 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 229 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 230 | version = "0.8.4" 231 | 232 | [[Fontconfig_jll]] 233 | deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] 234 | git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" 235 | uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" 236 | version = "2.13.93+0" 237 | 238 | [[Formatting]] 239 | deps = ["Printf"] 240 | git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" 241 | uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" 242 | version = "0.4.2" 243 | 244 | [[ForwardDiff]] 245 | deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] 246 | git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad" 247 | uuid = "f6369f11-7733-5829-9624-2563aa707210" 248 | version = "0.10.36" 249 | 250 | [[FreeType2_jll]] 251 | deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] 252 | git-tree-sha1 = "d8db6a5a2fe1381c1ea4ef2cab7c69c2de7f9ea0" 253 | uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" 254 | version = "2.13.1+0" 255 | 256 | [[FriBidi_jll]] 257 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 258 | git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" 259 | uuid = "559328eb-81f9-559d-9380-de523a88c83c" 260 | version = "1.0.10+0" 261 | 262 | [[GLFW_jll]] 263 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] 264 | git-tree-sha1 = "ff38ba61beff76b8f4acad8ab0c97ef73bb670cb" 265 | uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" 266 | version = "3.3.9+0" 267 | 268 | [[GPUArraysCore]] 269 | deps = ["Adapt"] 270 | git-tree-sha1 = "ec632f177c0d990e64d955ccc1b8c04c485a0950" 271 | uuid = "46192b85-c4d5-4398-a991-12ede77f4527" 272 | version = "0.1.6" 273 | 274 | [[GR]] 275 | deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Preferences", "Printf", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "UUIDs", "p7zip_jll"] 276 | git-tree-sha1 = "27442171f28c952804dede8ff72828a96f2bfc1f" 277 | uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" 278 | version = "0.72.10" 279 | 280 | [[GR_jll]] 281 | deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "FreeType2_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt6Base_jll", "Zlib_jll", "libpng_jll"] 282 | git-tree-sha1 = "025d171a2847f616becc0f84c8dc62fe18f0f6dd" 283 | uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" 284 | version = "0.72.10+0" 285 | 286 | [[GeoInterface]] 287 | deps = ["Extents"] 288 | git-tree-sha1 = "d4f85701f569584f2cff7ba67a137d03f0cfb7d0" 289 | uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" 290 | version = "1.3.3" 291 | 292 | [[GeometryBasics]] 293 | deps = ["EarCut_jll", "Extents", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] 294 | git-tree-sha1 = "5694b56ccf9d15addedc35e9a4ba9c317721b788" 295 | uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" 296 | version = "0.4.10" 297 | 298 | [[Gettext_jll]] 299 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] 300 | git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" 301 | uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" 302 | version = "0.21.0+0" 303 | 304 | [[Glib_jll]] 305 | deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] 306 | git-tree-sha1 = "e94c92c7bf4819685eb80186d51c43e71d4afa17" 307 | uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" 308 | version = "2.76.5+0" 309 | 310 | [[Graphite2_jll]] 311 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 312 | git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" 313 | uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" 314 | version = "1.3.14+0" 315 | 316 | [[Grisu]] 317 | git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" 318 | uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" 319 | version = "1.0.2" 320 | 321 | [[HTTP]] 322 | deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] 323 | git-tree-sha1 = "abbbb9ec3afd783a7cbd82ef01dcd088ea051398" 324 | uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" 325 | version = "1.10.1" 326 | 327 | [[HarfBuzz_jll]] 328 | deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] 329 | git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" 330 | uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" 331 | version = "2.8.1+1" 332 | 333 | [[InteractiveUtils]] 334 | deps = ["Markdown"] 335 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 336 | 337 | [[InverseFunctions]] 338 | deps = ["Test"] 339 | git-tree-sha1 = "68772f49f54b479fa88ace904f6127f0a3bb2e46" 340 | uuid = "3587e190-3f89-42d0-90ee-14403ec27112" 341 | version = "0.1.12" 342 | 343 | [[IrrationalConstants]] 344 | git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" 345 | uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" 346 | version = "0.2.2" 347 | 348 | [[IterTools]] 349 | git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" 350 | uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" 351 | version = "1.4.0" 352 | 353 | [[IteratorInterfaceExtensions]] 354 | git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" 355 | uuid = "82899510-4779-5014-852e-03e436cf321d" 356 | version = "1.0.0" 357 | 358 | [[JLFzf]] 359 | deps = ["Pipe", "REPL", "Random", "fzf_jll"] 360 | git-tree-sha1 = "a53ebe394b71470c7f97c2e7e170d51df21b17af" 361 | uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" 362 | version = "0.1.7" 363 | 364 | [[JLLWrappers]] 365 | deps = ["Artifacts", "Preferences"] 366 | git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" 367 | uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" 368 | version = "1.5.0" 369 | 370 | [[JSON]] 371 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 372 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 373 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 374 | version = "0.21.4" 375 | 376 | [[JpegTurbo_jll]] 377 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 378 | git-tree-sha1 = "60b1194df0a3298f460063de985eae7b01bc011a" 379 | uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" 380 | version = "3.0.1+0" 381 | 382 | [[LAME_jll]] 383 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 384 | git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" 385 | uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" 386 | version = "3.100.1+0" 387 | 388 | [[LERC_jll]] 389 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 390 | git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" 391 | uuid = "88015f11-f218-50d7-93a8-a6af411a945d" 392 | version = "3.0.0+1" 393 | 394 | [[LLVMOpenMP_jll]] 395 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 396 | git-tree-sha1 = "d986ce2d884d49126836ea94ed5bfb0f12679713" 397 | uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" 398 | version = "15.0.7+0" 399 | 400 | [[LZO_jll]] 401 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 402 | git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" 403 | uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" 404 | version = "2.10.1+0" 405 | 406 | [[LaTeXStrings]] 407 | git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" 408 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 409 | version = "1.3.1" 410 | 411 | [[Latexify]] 412 | deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Printf", "Requires"] 413 | git-tree-sha1 = "f428ae552340899a935973270b8d98e5a31c49fe" 414 | uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 415 | version = "0.16.1" 416 | 417 | [[LibCURL]] 418 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 419 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 420 | 421 | [[LibCURL_jll]] 422 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 423 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 424 | 425 | [[LibGit2]] 426 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 427 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 428 | 429 | [[LibSSH2_jll]] 430 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 431 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 432 | 433 | [[Libdl]] 434 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 435 | 436 | [[Libffi_jll]] 437 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 438 | git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" 439 | uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" 440 | version = "3.2.2+1" 441 | 442 | [[Libgcrypt_jll]] 443 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] 444 | git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" 445 | uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" 446 | version = "1.8.7+0" 447 | 448 | [[Libglvnd_jll]] 449 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] 450 | git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733" 451 | uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" 452 | version = "1.6.0+0" 453 | 454 | [[Libgpg_error_jll]] 455 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 456 | git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" 457 | uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" 458 | version = "1.42.0+0" 459 | 460 | [[Libiconv_jll]] 461 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 462 | git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175" 463 | uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" 464 | version = "1.17.0+0" 465 | 466 | [[Libmount_jll]] 467 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 468 | git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" 469 | uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" 470 | version = "2.35.0+0" 471 | 472 | [[Libtiff_jll]] 473 | deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] 474 | git-tree-sha1 = "2da088d113af58221c52828a80378e16be7d037a" 475 | uuid = "89763e89-9b03-5906-acba-b20f662cd828" 476 | version = "4.5.1+1" 477 | 478 | [[Libuuid_jll]] 479 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 480 | git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" 481 | uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" 482 | version = "2.36.0+0" 483 | 484 | [[LinearAlgebra]] 485 | deps = ["Libdl"] 486 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 487 | 488 | [[LogExpFunctions]] 489 | deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] 490 | git-tree-sha1 = "7d6dd4e9212aebaeed356de34ccf262a3cd415aa" 491 | uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" 492 | version = "0.3.26" 493 | 494 | [[Logging]] 495 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 496 | 497 | [[LoggingExtras]] 498 | deps = ["Dates", "Logging"] 499 | git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" 500 | uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" 501 | version = "1.0.3" 502 | 503 | [[MacroTools]] 504 | deps = ["Markdown", "Random"] 505 | git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" 506 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 507 | version = "0.5.13" 508 | 509 | [[Markdown]] 510 | deps = ["Base64"] 511 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 512 | 513 | [[MbedTLS]] 514 | deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] 515 | git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf" 516 | uuid = "739be429-bea8-5141-9913-cc70e7f3736d" 517 | version = "1.1.9" 518 | 519 | [[MbedTLS_jll]] 520 | deps = ["Artifacts", "Libdl"] 521 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 522 | 523 | [[Measures]] 524 | git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" 525 | uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" 526 | version = "0.3.2" 527 | 528 | [[MeshCat]] 529 | deps = ["Base64", "Cassette", "Colors", "CoordinateTransformations", "DocStringExtensions", "FFMPEG", "GeometryBasics", "HTTP", "LinearAlgebra", "Logging", "MsgPack", "Parameters", "Pkg", "Requires", "Rotations", "Sockets", "StaticArrays", "Tar", "UUIDs"] 530 | git-tree-sha1 = "36d71bbe7a4279641d84df1fa98bfa29561edd14" 531 | uuid = "283c5d60-a78f-5afe-a0af-af636b173e11" 532 | version = "0.16.0" 533 | 534 | [[Missings]] 535 | deps = ["DataAPI"] 536 | git-tree-sha1 = "f66bdc5de519e8f8ae43bdc598782d35a25b1272" 537 | uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" 538 | version = "1.1.0" 539 | 540 | [[Mmap]] 541 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 542 | 543 | [[MozillaCACerts_jll]] 544 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 545 | 546 | [[MsgPack]] 547 | deps = ["Serialization"] 548 | git-tree-sha1 = "f5db02ae992c260e4826fe78c942954b48e1d9c2" 549 | uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671" 550 | version = "1.2.1" 551 | 552 | [[NaNMath]] 553 | deps = ["OpenLibm_jll"] 554 | git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" 555 | uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" 556 | version = "1.0.2" 557 | 558 | [[NetworkOptions]] 559 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 560 | 561 | [[Ogg_jll]] 562 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 563 | git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" 564 | uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" 565 | version = "1.3.5+1" 566 | 567 | [[OpenLibm_jll]] 568 | deps = ["Artifacts", "Libdl"] 569 | uuid = "05823500-19ac-5b8b-9628-191a04bc5112" 570 | 571 | [[OpenSSL]] 572 | deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] 573 | git-tree-sha1 = "51901a49222b09e3743c65b8847687ae5fc78eb2" 574 | uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" 575 | version = "1.4.1" 576 | 577 | [[OpenSSL_jll]] 578 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 579 | git-tree-sha1 = "cc6e1927ac521b659af340e0ca45828a3ffc748f" 580 | uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" 581 | version = "3.0.12+0" 582 | 583 | [[OpenSpecFun_jll]] 584 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 585 | git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" 586 | uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" 587 | version = "0.5.5+0" 588 | 589 | [[Opus_jll]] 590 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 591 | git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" 592 | uuid = "91d4177d-7536-5919-b921-800302f37372" 593 | version = "1.3.2+0" 594 | 595 | [[OrderedCollections]] 596 | git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" 597 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 598 | version = "1.6.3" 599 | 600 | [[PCRE2_jll]] 601 | deps = ["Artifacts", "Libdl"] 602 | uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" 603 | 604 | [[PDMats]] 605 | deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] 606 | git-tree-sha1 = "949347156c25054de2db3b166c52ac4728cbad65" 607 | uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" 608 | version = "0.11.31" 609 | 610 | [[Parameters]] 611 | deps = ["OrderedCollections", "UnPack"] 612 | git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" 613 | uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" 614 | version = "0.12.3" 615 | 616 | [[Parsers]] 617 | deps = ["Dates", "PrecompileTools", "UUIDs"] 618 | git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" 619 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 620 | version = "2.8.1" 621 | 622 | [[Pipe]] 623 | git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d" 624 | uuid = "b98c9c47-44ae-5843-9183-064241ee97a0" 625 | version = "1.3.0" 626 | 627 | [[Pixman_jll]] 628 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] 629 | git-tree-sha1 = "64779bc4c9784fee475689a1752ef4d5747c5e87" 630 | uuid = "30392449-352a-5448-841d-b1acce4e97dc" 631 | version = "0.42.2+0" 632 | 633 | [[Pkg]] 634 | deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 635 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 636 | 637 | [[PlotThemes]] 638 | deps = ["PlotUtils", "Statistics"] 639 | git-tree-sha1 = "1f03a2d339f42dca4a4da149c7e15e9b896ad899" 640 | uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" 641 | version = "3.1.0" 642 | 643 | [[PlotUtils]] 644 | deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"] 645 | git-tree-sha1 = "862942baf5663da528f66d24996eb6da85218e76" 646 | uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" 647 | version = "1.4.0" 648 | 649 | [[Plots]] 650 | deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Preferences", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] 651 | git-tree-sha1 = "ccee59c6e48e6f2edf8a5b64dc817b6729f99eb5" 652 | uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 653 | version = "1.39.0" 654 | 655 | [[PrecompileTools]] 656 | deps = ["Preferences"] 657 | git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f" 658 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 659 | version = "1.2.0" 660 | 661 | [[Preferences]] 662 | deps = ["TOML"] 663 | git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" 664 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 665 | version = "1.4.1" 666 | 667 | [[Printf]] 668 | deps = ["Unicode"] 669 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 670 | 671 | [[Qt6Base_jll]] 672 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Vulkan_Loader_jll", "Xorg_libSM_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_cursor_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "libinput_jll", "xkbcommon_jll"] 673 | git-tree-sha1 = "37b7bb7aabf9a085e0044307e1717436117f2b3b" 674 | uuid = "c0090381-4147-56d7-9ebc-da0b1113ec56" 675 | version = "6.5.3+1" 676 | 677 | [[Quaternions]] 678 | deps = ["LinearAlgebra", "Random", "RealDot"] 679 | git-tree-sha1 = "9a46862d248ea548e340e30e2894118749dc7f51" 680 | uuid = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0" 681 | version = "0.7.5" 682 | 683 | [[REPL]] 684 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 685 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 686 | 687 | [[Random]] 688 | deps = ["Serialization"] 689 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 690 | 691 | [[RealDot]] 692 | deps = ["LinearAlgebra"] 693 | git-tree-sha1 = "9f0a1b71baaf7650f4fa8a1d168c7fb6ee41f0c9" 694 | uuid = "c1ae055f-0cd5-4b69-90a6-9a35b1a98df9" 695 | version = "0.1.0" 696 | 697 | [[RecipesBase]] 698 | deps = ["PrecompileTools"] 699 | git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" 700 | uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" 701 | version = "1.3.4" 702 | 703 | [[RecipesPipeline]] 704 | deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"] 705 | git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342" 706 | uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" 707 | version = "0.6.12" 708 | 709 | [[Reexport]] 710 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 711 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 712 | version = "1.2.2" 713 | 714 | [[RelocatableFolders]] 715 | deps = ["SHA", "Scratch"] 716 | git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864" 717 | uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" 718 | version = "1.0.1" 719 | 720 | [[Requires]] 721 | deps = ["UUIDs"] 722 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 723 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 724 | version = "1.3.0" 725 | 726 | [[Richardson]] 727 | deps = ["LinearAlgebra"] 728 | git-tree-sha1 = "48f038bfd83344065434089c2a79417f38715c41" 729 | uuid = "708f8203-808e-40c0-ba2d-98a6953ed40d" 730 | version = "1.4.2" 731 | 732 | [[Rotations]] 733 | deps = ["LinearAlgebra", "Quaternions", "Random", "StaticArrays"] 734 | git-tree-sha1 = "792d8fd4ad770b6d517a13ebb8dadfcac79405b8" 735 | uuid = "6038ab10-8711-5258-84ad-4b1120ba62dc" 736 | version = "1.6.1" 737 | 738 | [[SHA]] 739 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 740 | 741 | [[Scratch]] 742 | deps = ["Dates"] 743 | git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" 744 | uuid = "6c6a2e73-6563-6170-7368-637461726353" 745 | version = "1.2.1" 746 | 747 | [[Serialization]] 748 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 749 | 750 | [[Showoff]] 751 | deps = ["Dates", "Grisu"] 752 | git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" 753 | uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" 754 | version = "1.0.3" 755 | 756 | [[SimpleBufferStream]] 757 | git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" 758 | uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" 759 | version = "1.1.0" 760 | 761 | [[Sockets]] 762 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 763 | 764 | [[SortingAlgorithms]] 765 | deps = ["DataStructures"] 766 | git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" 767 | uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" 768 | version = "1.2.1" 769 | 770 | [[SparseArrays]] 771 | deps = ["LinearAlgebra", "Random"] 772 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 773 | 774 | [[SpecialFunctions]] 775 | deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] 776 | git-tree-sha1 = "e2cfc4012a19088254b3950b85c3c1d8882d864d" 777 | uuid = "276daf66-3868-5448-9aa4-cd146d93841b" 778 | version = "2.3.1" 779 | 780 | [[StaticArrays]] 781 | deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore", "Statistics"] 782 | git-tree-sha1 = "f68dd04d131d9a8a8eb836173ee8f105c360b0c5" 783 | uuid = "90137ffa-7385-5640-81b9-e52037218182" 784 | version = "1.9.1" 785 | 786 | [[StaticArraysCore]] 787 | git-tree-sha1 = "36b3d696ce6366023a0ea192b4cd442268995a0d" 788 | uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" 789 | version = "1.4.2" 790 | 791 | [[Statistics]] 792 | deps = ["LinearAlgebra", "SparseArrays"] 793 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 794 | 795 | [[StatsAPI]] 796 | deps = ["LinearAlgebra"] 797 | git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" 798 | uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" 799 | version = "1.7.0" 800 | 801 | [[StatsBase]] 802 | deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] 803 | git-tree-sha1 = "1d77abd07f617c4868c33d4f5b9e1dbb2643c9cf" 804 | uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" 805 | version = "0.34.2" 806 | 807 | [[StructArrays]] 808 | deps = ["Adapt", "ConstructionBase", "DataAPI", "GPUArraysCore", "StaticArraysCore", "Tables"] 809 | git-tree-sha1 = "1b0b1205a56dc288b71b1961d48e351520702e24" 810 | uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" 811 | version = "0.6.17" 812 | 813 | [[SuiteSparse]] 814 | deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] 815 | uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" 816 | 817 | [[TOML]] 818 | deps = ["Dates"] 819 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 820 | 821 | [[TableTraits]] 822 | deps = ["IteratorInterfaceExtensions"] 823 | git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" 824 | uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" 825 | version = "1.0.1" 826 | 827 | [[Tables]] 828 | deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"] 829 | git-tree-sha1 = "cb76cf677714c095e535e3501ac7954732aeea2d" 830 | uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" 831 | version = "1.11.1" 832 | 833 | [[Tar]] 834 | deps = ["ArgTools", "SHA"] 835 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 836 | 837 | [[TensorCore]] 838 | deps = ["LinearAlgebra"] 839 | git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" 840 | uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" 841 | version = "0.1.1" 842 | 843 | [[Test]] 844 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 845 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 846 | 847 | [[TranscodingStreams]] 848 | deps = ["Random", "Test"] 849 | git-tree-sha1 = "1fbeaaca45801b4ba17c251dd8603ef24801dd84" 850 | uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" 851 | version = "0.10.2" 852 | 853 | [[URIs]] 854 | git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" 855 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 856 | version = "1.5.1" 857 | 858 | [[UUIDs]] 859 | deps = ["Random", "SHA"] 860 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 861 | 862 | [[UnPack]] 863 | git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" 864 | uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" 865 | version = "1.0.2" 866 | 867 | [[Unicode]] 868 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 869 | 870 | [[UnicodeFun]] 871 | deps = ["REPL"] 872 | git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" 873 | uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" 874 | version = "0.4.1" 875 | 876 | [[Unitful]] 877 | deps = ["ConstructionBase", "Dates", "InverseFunctions", "LinearAlgebra", "Random"] 878 | git-tree-sha1 = "3c793be6df9dd77a0cf49d80984ef9ff996948fa" 879 | uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" 880 | version = "1.19.0" 881 | 882 | [[UnitfulLatexify]] 883 | deps = ["LaTeXStrings", "Latexify", "Unitful"] 884 | git-tree-sha1 = "e2d817cc500e960fdbafcf988ac8436ba3208bfd" 885 | uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" 886 | version = "1.6.3" 887 | 888 | [[Unzip]] 889 | git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" 890 | uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" 891 | version = "0.1.2" 892 | 893 | [[Vulkan_Loader_jll]] 894 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Wayland_jll", "Xorg_libX11_jll", "Xorg_libXrandr_jll", "xkbcommon_jll"] 895 | git-tree-sha1 = "2f0486047a07670caad3a81a075d2e518acc5c59" 896 | uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c" 897 | version = "1.3.243+0" 898 | 899 | [[Wayland_jll]] 900 | deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] 901 | git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703" 902 | uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" 903 | version = "1.21.0+1" 904 | 905 | [[Wayland_protocols_jll]] 906 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 907 | git-tree-sha1 = "93f43ab61b16ddfb2fd3bb13b3ce241cafb0e6c9" 908 | uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" 909 | version = "1.31.0+0" 910 | 911 | [[XML2_jll]] 912 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] 913 | git-tree-sha1 = "801cbe47eae69adc50f36c3caec4758d2650741b" 914 | uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" 915 | version = "2.12.2+0" 916 | 917 | [[XSLT_jll]] 918 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] 919 | git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" 920 | uuid = "aed1982a-8fda-507f-9586-7b0439959a61" 921 | version = "1.1.34+0" 922 | 923 | [[XZ_jll]] 924 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 925 | git-tree-sha1 = "522b8414d40c4cbbab8dee346ac3a09f9768f25d" 926 | uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800" 927 | version = "5.4.5+0" 928 | 929 | [[Xorg_libICE_jll]] 930 | deps = ["Libdl", "Pkg"] 931 | git-tree-sha1 = "e5becd4411063bdcac16be8b66fc2f9f6f1e8fe5" 932 | uuid = "f67eecfb-183a-506d-b269-f58e52b52d7c" 933 | version = "1.0.10+1" 934 | 935 | [[Xorg_libSM_jll]] 936 | deps = ["Libdl", "Pkg", "Xorg_libICE_jll"] 937 | git-tree-sha1 = "4a9d9e4c180e1e8119b5ffc224a7b59d3a7f7e18" 938 | uuid = "c834827a-8449-5923-a945-d239c165b7dd" 939 | version = "1.2.3+0" 940 | 941 | [[Xorg_libX11_jll]] 942 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] 943 | git-tree-sha1 = "afead5aba5aa507ad5a3bf01f58f82c8d1403495" 944 | uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" 945 | version = "1.8.6+0" 946 | 947 | [[Xorg_libXau_jll]] 948 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 949 | git-tree-sha1 = "6035850dcc70518ca32f012e46015b9beeda49d8" 950 | uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" 951 | version = "1.0.11+0" 952 | 953 | [[Xorg_libXcursor_jll]] 954 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] 955 | git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" 956 | uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" 957 | version = "1.2.0+4" 958 | 959 | [[Xorg_libXdmcp_jll]] 960 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 961 | git-tree-sha1 = "34d526d318358a859d7de23da945578e8e8727b7" 962 | uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" 963 | version = "1.1.4+0" 964 | 965 | [[Xorg_libXext_jll]] 966 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 967 | git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" 968 | uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" 969 | version = "1.3.4+4" 970 | 971 | [[Xorg_libXfixes_jll]] 972 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 973 | git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" 974 | uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" 975 | version = "5.0.3+4" 976 | 977 | [[Xorg_libXi_jll]] 978 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] 979 | git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" 980 | uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" 981 | version = "1.7.10+4" 982 | 983 | [[Xorg_libXinerama_jll]] 984 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] 985 | git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" 986 | uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" 987 | version = "1.1.4+4" 988 | 989 | [[Xorg_libXrandr_jll]] 990 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] 991 | git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" 992 | uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" 993 | version = "1.5.2+4" 994 | 995 | [[Xorg_libXrender_jll]] 996 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 997 | git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" 998 | uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" 999 | version = "0.9.10+4" 1000 | 1001 | [[Xorg_libpthread_stubs_jll]] 1002 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 1003 | git-tree-sha1 = "8fdda4c692503d44d04a0603d9ac0982054635f9" 1004 | uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" 1005 | version = "0.1.1+0" 1006 | 1007 | [[Xorg_libxcb_jll]] 1008 | deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] 1009 | git-tree-sha1 = "b4bfde5d5b652e22b9c790ad00af08b6d042b97d" 1010 | uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" 1011 | version = "1.15.0+0" 1012 | 1013 | [[Xorg_libxkbfile_jll]] 1014 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] 1015 | git-tree-sha1 = "730eeca102434283c50ccf7d1ecdadf521a765a4" 1016 | uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" 1017 | version = "1.1.2+0" 1018 | 1019 | [[Xorg_xcb_util_cursor_jll]] 1020 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_jll", "Xorg_xcb_util_renderutil_jll"] 1021 | git-tree-sha1 = "04341cb870f29dcd5e39055f895c39d016e18ccd" 1022 | uuid = "e920d4aa-a673-5f3a-b3d7-f755a4d47c43" 1023 | version = "0.1.4+0" 1024 | 1025 | [[Xorg_xcb_util_image_jll]] 1026 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1027 | git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" 1028 | uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" 1029 | version = "0.4.0+1" 1030 | 1031 | [[Xorg_xcb_util_jll]] 1032 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] 1033 | git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" 1034 | uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" 1035 | version = "0.4.0+1" 1036 | 1037 | [[Xorg_xcb_util_keysyms_jll]] 1038 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1039 | git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" 1040 | uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" 1041 | version = "0.4.0+1" 1042 | 1043 | [[Xorg_xcb_util_renderutil_jll]] 1044 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1045 | git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" 1046 | uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" 1047 | version = "0.3.9+1" 1048 | 1049 | [[Xorg_xcb_util_wm_jll]] 1050 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1051 | git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" 1052 | uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" 1053 | version = "0.4.1+1" 1054 | 1055 | [[Xorg_xkbcomp_jll]] 1056 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"] 1057 | git-tree-sha1 = "330f955bc41bb8f5270a369c473fc4a5a4e4d3cb" 1058 | uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" 1059 | version = "1.4.6+0" 1060 | 1061 | [[Xorg_xkeyboard_config_jll]] 1062 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"] 1063 | git-tree-sha1 = "691634e5453ad362044e2ad653e79f3ee3bb98c3" 1064 | uuid = "33bec58e-1273-512f-9401-5d533626f822" 1065 | version = "2.39.0+0" 1066 | 1067 | [[Xorg_xtrans_jll]] 1068 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 1069 | git-tree-sha1 = "e92a1a012a10506618f10b7047e478403a046c77" 1070 | uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" 1071 | version = "1.5.0+0" 1072 | 1073 | [[Zlib_jll]] 1074 | deps = ["Libdl"] 1075 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 1076 | 1077 | [[Zstd_jll]] 1078 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 1079 | git-tree-sha1 = "49ce682769cd5de6c72dcf1b94ed7790cd08974c" 1080 | uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" 1081 | version = "1.5.5+0" 1082 | 1083 | [[eudev_jll]] 1084 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "gperf_jll"] 1085 | git-tree-sha1 = "431b678a28ebb559d224c0b6b6d01afce87c51ba" 1086 | uuid = "35ca27e7-8b34-5b7f-bca9-bdc33f59eb06" 1087 | version = "3.2.9+0" 1088 | 1089 | [[fzf_jll]] 1090 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 1091 | git-tree-sha1 = "a68c9655fbe6dfcab3d972808f1aafec151ce3f8" 1092 | uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" 1093 | version = "0.43.0+0" 1094 | 1095 | [[gperf_jll]] 1096 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1097 | git-tree-sha1 = "3516a5630f741c9eecb3720b1ec9d8edc3ecc033" 1098 | uuid = "1a1c6b14-54f6-533d-8383-74cd7377aa70" 1099 | version = "3.1.1+0" 1100 | 1101 | [[libaom_jll]] 1102 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1103 | git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" 1104 | uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" 1105 | version = "3.4.0+0" 1106 | 1107 | [[libass_jll]] 1108 | deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] 1109 | git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" 1110 | uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" 1111 | version = "0.15.1+0" 1112 | 1113 | [[libevdev_jll]] 1114 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1115 | git-tree-sha1 = "141fe65dc3efabb0b1d5ba74e91f6ad26f84cc22" 1116 | uuid = "2db6ffa8-e38f-5e21-84af-90c45d0032cc" 1117 | version = "1.11.0+0" 1118 | 1119 | [[libfdk_aac_jll]] 1120 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1121 | git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" 1122 | uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" 1123 | version = "2.0.2+0" 1124 | 1125 | [[libinput_jll]] 1126 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "eudev_jll", "libevdev_jll", "mtdev_jll"] 1127 | git-tree-sha1 = "ad50e5b90f222cfe78aa3d5183a20a12de1322ce" 1128 | uuid = "36db933b-70db-51c0-b978-0f229ee0e533" 1129 | version = "1.18.0+0" 1130 | 1131 | [[libpng_jll]] 1132 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] 1133 | git-tree-sha1 = "93284c28274d9e75218a416c65ec49d0e0fcdf3d" 1134 | uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" 1135 | version = "1.6.40+0" 1136 | 1137 | [[libvorbis_jll]] 1138 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] 1139 | git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" 1140 | uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" 1141 | version = "1.3.7+1" 1142 | 1143 | [[mtdev_jll]] 1144 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1145 | git-tree-sha1 = "814e154bdb7be91d78b6802843f76b6ece642f11" 1146 | uuid = "009596ad-96f7-51b1-9f1b-5ce2d5e8a71e" 1147 | version = "1.1.6+0" 1148 | 1149 | [[nghttp2_jll]] 1150 | deps = ["Artifacts", "Libdl"] 1151 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 1152 | 1153 | [[p7zip_jll]] 1154 | deps = ["Artifacts", "Libdl"] 1155 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 1156 | 1157 | [[x264_jll]] 1158 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1159 | git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" 1160 | uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" 1161 | version = "2021.5.5+0" 1162 | 1163 | [[x265_jll]] 1164 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1165 | git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" 1166 | uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" 1167 | version = "3.5.0+0" 1168 | 1169 | [[xkbcommon_jll]] 1170 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] 1171 | git-tree-sha1 = "9c304562909ab2bab0262639bd4f444d7bc2be37" 1172 | uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" 1173 | version = "1.4.1+1" 1174 | -------------------------------------------------------------------------------- /examples/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | BlockDiagonals = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0" 3 | ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 4 | CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298" 5 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 6 | GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" 7 | Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 8 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 9 | MeshCat = "283c5d60-a78f-5afe-a0af-af636b173e11" 10 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 11 | Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" 12 | -------------------------------------------------------------------------------- /examples/interactive_cartpole_ext.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Julia Interactive Example: TinyMPC on Cartpole (Extended Version)\n", 9 | "In this demonstration, we showcase an interactive Julia workflow using TinyMPC. You can generate C++ code and engage with it seamlessly within the Julia environment. This example guides you through the entire workflow, beginning with the cartpole's nonlinear dynamics.\n", 10 | "\n", 11 | "If any issues arise, restart the kernel." 12 | ] 13 | }, 14 | { 15 | "attachments": {}, 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "Load necessary packages, make sure to install `tinympc` ([README.md](../README.md))" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "import Pkg;\n", 29 | "Pkg.activate(@__DIR__);\n", 30 | "Pkg.instantiate()\n", 31 | "\n", 32 | "using Libdl\n", 33 | "using LinearAlgebra\n", 34 | "import ForwardDiff as FD\n", 35 | "\n", 36 | "include(joinpath(@__DIR__,\"../tinympc/TinyMPC.jl\"))\n", 37 | "using .TinyMPC\n", 38 | "include(\"visualization.jl\") # for visualization" 39 | ] 40 | }, 41 | { 42 | "attachments": {}, 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "## Cartpole Dynamics\n", 47 | "Build the cartpole nonlinear dynamics and linearize around upright state using `ForwardDiff`. " 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "freq = 100 # frequency of the controller and dynamics Hz\n", 57 | "dt = 1/freq # time step\n", 58 | "\n", 59 | "# cartpole dynamics with theta = 0 at the down position\n", 60 | "function cartpole_dynamics(x::Vector, u::Vector)\n", 61 | " g = -9.8 # gravity m/s^2\n", 62 | " m = 0.2 # mass of the pole kg\n", 63 | " M = 0.5 # mass of the cart kg\n", 64 | " l = 0.3 # length of the pole m\n", 65 | "\n", 66 | " x, x_dot, theta, theta_dot = x\n", 67 | " u = u[1]\n", 68 | "\n", 69 | " x_ddot = (u + m * l * theta_dot^2 * sin(theta) - m * g * sin(theta) * cos(theta)) / (M + m * sin(theta)^2)\n", 70 | " theta_ddot = (-u * cos(theta) - m * l * theta_dot^2 * sin(theta) * cos(theta) + (M + m) * g * sin(theta)) / (l * (M + m * sin(theta)^2))\n", 71 | "\n", 72 | " return [x_dot, x_ddot, theta_dot, theta_ddot]\n", 73 | "end \n", 74 | "function rk4(x::Vector, u::Vector)\n", 75 | " f = cartpole_dynamics\n", 76 | " k1 = f(x, u)\n", 77 | " k2 = f(x + dt * k1 / 2, u)\n", 78 | " k3 = f(x + dt * k2 / 2, u)\n", 79 | " k4 = f(x + dt * k3, u)\n", 80 | " return x + dt / 6 * (k1 + 2 * k2 + 2 * k3 + k4)\n", 81 | "end\n", 82 | "function cartpole_dynamics_rk4(x::Vector, u::Vector)\n", 83 | " return rk4(x, u)\n", 84 | "end\n", 85 | "\n", 86 | "# Linearize the dynamics around x0, u0\n", 87 | "x0 = [0, 0, pi, 0.0]\n", 88 | "u0 = [0.]\n", 89 | "Anp = FD.jacobian(x -> cartpole_dynamics_rk4(x, u0), x0)\n", 90 | "Bnp = FD.jacobian(u -> cartpole_dynamics_rk4(x0, u), u0)\n", 91 | "display(Anp)\n", 92 | "display(Bnp)" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "x_all = [zeros(4) for i in 1:300]\n", 102 | "# simulate the dynamics with the zero controller\n", 103 | "x = [0, 0, 0.1, 0]\n", 104 | "for i in 1:300\n", 105 | " x = cartpole_dynamics_rk4(x, u0)\n", 106 | " x_all[i] = x\n", 107 | "end\n", 108 | "# Go to the visualization part at the end and run it to see the trajectory `x_all`" 109 | ] 110 | }, 111 | { 112 | "attachments": {}, 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "## LQR Controller\n", 117 | "\n", 118 | "Let's run LQR on the linearized model" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# Riccati recursion on the linearized dynamics\n", 128 | "Q = Diagonal([10, 1, 10, 1.])\n", 129 | "R = Diagonal([1.])\n", 130 | "P = 1*Q\n", 131 | "K = zeros(1, 4)\n", 132 | "for i in 1:100\n", 133 | " P = Q + Anp' * P * Anp - Anp' * P * Bnp * inv(R + Bnp' * P * Bnp) * Bnp' * P * Anp\n", 134 | " K = inv(R + Bnp' * P * Bnp) * Bnp' * P * Anp\n", 135 | "end\n", 136 | "display(K)\n", 137 | "\n", 138 | "# LQR controller\n", 139 | "function lqr_controller(x::Vector)\n", 140 | " return -K * x\n", 141 | "end\n", 142 | "\n", 143 | "# simulate the dynamics with the LQR controller\n", 144 | "x = [0, 0, pi - 0.1, 0.0] # initial state\n", 145 | "for i in 1:300\n", 146 | " u = lqr_controller(x - x0)\n", 147 | " x = cartpole_dynamics_rk4(x, u)\n", 148 | " x_all[i] = x\n", 149 | "end\n", 150 | "# Go to the visualization part at the end and run it to see the trajectory `x_all`" 151 | ] 152 | }, 153 | { 154 | "attachments": {}, 155 | "cell_type": "markdown", 156 | "metadata": {}, 157 | "source": [ 158 | "## Code Generation\n", 159 | "\n", 160 | "We are done with the dynamics and LQR controller. Now, let's define the class and compile original TinyMPC code to get a generic shared/dynamic library\n", 161 | "\n", 162 | "**PLEASE CHANGE `tinympc_julia_dir` TO YOUR ABSOLUTE PATH**" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "tinympc_julia_dir = \"/home/khai/SSD/Code/tinympc-julia\" # Your absolute path to the tinympc-Julia directory, you need to change this\n", 172 | "tinympc_dir = tinympc_julia_dir * \"/tinympc/TinyMPC\" # Path to the TinyMPC directory (C code)\n", 173 | "TinyMPC.compile_lib(tinympc_dir) # Compile the C code into a shared library" 174 | ] 175 | }, 176 | { 177 | "attachments": {}, 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "Load the generic shared/dynamic library. **You may want to change the extension of the library based on your OS -- Linux: .so, Mac: .dylib, Windows: .dll**" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "os_ext = \".so\" # CHANGE THIS BASED ON YOUR OS\n", 191 | "tinympc = tinympc_dir * \"/build/src/tinympc/libtinympcShared\" * os_ext # Path to the compiled library" 192 | ] 193 | }, 194 | { 195 | "attachments": {}, 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "Here we setup problem data and settings for TinyMPC" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "n = 4\n", 209 | "m = 1\n", 210 | "N = 10\n", 211 | "\n", 212 | "# convert A to array column major\n", 213 | "# A = Array{Float32}(cat(Anp..., dims=2))[:]\n", 214 | "A = cat(Anp..., dims=2)[:]\n", 215 | "B = cat(Bnp..., dims=2)[:]\n", 216 | "display(A')\n", 217 | "display(B')\n", 218 | "Q = [10.0, 1, 10, 1]\n", 219 | "R = [1.0]\n", 220 | "rho = 0.1\n", 221 | "\n", 222 | "x_min = -5. * ones(n*N) # state constraints\n", 223 | "x_max = 5. * ones(n*N) # state constraints\n", 224 | "u_min = -5 * ones(m*(N-1)) # force constraints\n", 225 | "u_max = 5 * ones(m*(N-1)) # force constraints\n", 226 | "\n", 227 | "abs_pri_tol = 1.0e-3 # absolute primal tolerance\n", 228 | "abs_dual_tol = 1.0e-3 # absolute dual tolerance\n", 229 | "max_iter = 100 # maximum number of iterations\n", 230 | "check_termination = 1 # whether to check termination and period" 231 | ] 232 | }, 233 | { 234 | "attachments": {}, 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "After define the problem, we generate the tailored code with above data. \n", 239 | "\n", 240 | "**Here we compile it for interactive Julia script but you can use it directly for your applications/systems**\n", 241 | "\n", 242 | "Since Julia does JIT compilation, we cannot wrap C functions now -- we haven't generated the C code yet!. Therefore, we need to call the C function using `ccall` directly, which doesn't look nice :(" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": null, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "output_dir = tinympc_julia_dir * \"/generated_code1\" # Path to the generated code\n", 252 | "\n", 253 | "@ccall tinympc.tiny_codegen(n::Cint, m::Cint, N::Cint, A::Ptr{Float64}, B::Ptr{Float64}, Q::Ptr{Float64}, R::Ptr{Float64}, x_min::Ptr{Float64}, x_max::Ptr{Float64}, u_min::Ptr{Float64}, u_max::Ptr{Float64}, rho::Float64, abs_pri_tol::Float64, abs_dual_tol::Float64, max_iter::Cint, check_termination::Cint, 1::Cint, tinympc_dir::Ptr{UInt8}, output_dir::Ptr{UInt8})::Cint\n", 254 | "\n", 255 | "TinyMPC.compile_lib(output_dir)" 256 | ] 257 | }, 258 | { 259 | "attachments": {}, 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "## Interactive MPC\n", 264 | "\n", 265 | "Run the interactive MPC example which calls the generated code, use nonlinear dynamics for simulation\n", 266 | "\n", 267 | "Since this works with pointers, underlying data is persistent in each kernel session (something like deepcopy/shallowcopy or pass by reference/value). If you want to run from the original setup, you may need to change data back or \n", 268 | "restart kernel." 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": 1, 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "ename": "UndefVarError", 278 | "evalue": "UndefVarError: n not defined", 279 | "output_type": "error", 280 | "traceback": [ 281 | "UndefVarError: n not defined\n", 282 | "\n", 283 | "Stacktrace:\n", 284 | " [1] (::var\"#9#10\")(i::Int64)\n", 285 | " @ Main ./none:0\n", 286 | " [2] iterate\n", 287 | " @ ./generator.jl:47 [inlined]\n", 288 | " [3] collect(itr::Base.Generator{UnitRange{Int64}, var\"#9#10\"})\n", 289 | " @ Base ./array.jl:681\n", 290 | " [4] top-level scope\n", 291 | " @ ~/SSD/Code/tinympc-julia/examples/interactive_cartpole_ext.ipynb:2" 292 | ] 293 | } 294 | ], 295 | "source": [ 296 | "NSIM = 400\n", 297 | "x_all = [zeros(n) for i in 1:NSIM]\n", 298 | "\n", 299 | "tinympc = output_dir * \"/build/tinympc/libtinympcShared\" * os_ext # Path to the compiled library\n", 300 | "\n", 301 | "x = [0.5, 0, -0.4 + pi, 0.1] # Initial state\n", 302 | "u = Array{Float32}(zeros(m*(N-1))) # List of control inputs in horizon\n", 303 | "\n", 304 | "delta_x_noise = Array{Float32}(x - x0)\n", 305 | "\n", 306 | "# Use delta because MPC uses the linearized dynamics around upright position\n", 307 | "# Set the reference state to 0 as well as reset\n", 308 | "delta_xref = Array{Float32}(zeros(n*N)) # reference state\n", 309 | "@ccall tinympc.set_xref(delta_xref::Ptr{Float32}, 0::Cint)::Cvoid\n", 310 | "\n", 311 | "# Set the reference x to 1 at step 200\n", 312 | "delta_xref_new_ = [[1.0, 0, 0, 0] for i in 1:N]\n", 313 | "delta_xref_new = Array{Float32}(cat(delta_xref_new_..., dims=2))[:]\n", 314 | "\n", 315 | "\n", 316 | "for i in 1:NSIM\n", 317 | " # 1. Set initial state from measurement \n", 318 | " @ccall tinympc.set_x0(delta_x_noise::Ptr{Float32}, 0::Cint)::Cvoid\n", 319 | "\n", 320 | " # 2. Set the reference state if needed\n", 321 | " # At step 200, set x = 1\n", 322 | " if (i==200)\n", 323 | " @ccall tinympc.set_xref(delta_xref_new::Ptr{Float32}, 0::Cint)::Cvoid\n", 324 | " end\n", 325 | "\n", 326 | " # 3. Solve the problem\n", 327 | " @ccall tinympc.call_tiny_solve(0::Cint)::Cvoid\n", 328 | "\n", 329 | " # 4. Get the control input\n", 330 | " @ccall tinympc.get_u(u::Ptr{Float32}, 0::Cint)::Cvoid\n", 331 | "\n", 332 | " # 5. Simulate the dynamics\n", 333 | " x = cartpole_dynamics_rk4(x, u)\n", 334 | "\n", 335 | " noise = randn(n) * 0.01\n", 336 | " delta_x_noise = Array{Float32}(x + noise - x0)\n", 337 | " x_all[i] = x\n", 338 | "end\n" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "# Visualize the result (may take some time)\n", 348 | "display(animate_cartpole(x_all, dt))" 349 | ] 350 | }, 351 | { 352 | "attachments": {}, 353 | "cell_type": "markdown", 354 | "metadata": {}, 355 | "source": [ 356 | "## Deployment\n", 357 | "\n", 358 | "Post testing the MPC procedure with the generated code, the next step involves deploying it for your specific applications/systems.\n", 359 | "The workflow for deployment is tailored to your specific needs, and we aim to provide clear guidance.\n", 360 | "\n", 361 | "Your `tiny_main` may look like this\n", 362 | "\n", 363 | "```C\n", 364 | "int main()\n", 365 | "{\n", 366 | " int exitflag = 1;\n", 367 | " TinyWorkspace* work = tiny_data_solver.work;\n", 368 | " tiny_data_solver.work->Xref = tiny_MatrixNxNh::Zero();\n", 369 | " tiny_data_solver.work->Uref = tiny_MatrixNuNhm1::Zero();\n", 370 | " tiny_data_solver.settings->max_iter = 150;\n", 371 | " tiny_data_solver.settings->en_input_bound = 1;\n", 372 | " tiny_data_solver.settings->en_state_bound = 1;\n", 373 | "\n", 374 | " tiny_VectorNx x0, x1; // current and next simulation states\n", 375 | " x0 << 0.0, 0, 0.1, 0; // initial state\n", 376 | "\n", 377 | " int i = 0;\n", 378 | " for (int k = 0; k < 300; ++k)\n", 379 | " {\n", 380 | " printf(\"tracking error at step %2d: %.4f\\n\", k, (x0 - work->Xref.col(1)).norm());\n", 381 | "\n", 382 | " // 1. Update measurement\n", 383 | " work->x.col(0) = x0;\n", 384 | "\n", 385 | " // 2. Update reference (if needed)\n", 386 | " // you can also use C wrapper (intended for high-level languages) \n", 387 | " // by including tiny_wrapper.hpp and call `set_xref(...)` function\n", 388 | "\n", 389 | " // 3. Reset dual variables (if needed)\n", 390 | " work->y = tiny_MatrixNuNhm1::Zero();\n", 391 | " work->g = tiny_MatrixNxNh::Zero();\n", 392 | "\n", 393 | " // 4. Solve MPC problem\n", 394 | " exitflag = tiny_solve(&tiny_data_solver);\n", 395 | "\n", 396 | " // if (exitflag == 0)\n", 397 | " // \tprintf(\"HOORAY! Solved with no error!\\n\");\n", 398 | " // else\n", 399 | " // \tprintf(\"OOPS! Something went wrong!\\n\");\n", 400 | " // \t// break;\n", 401 | "\n", 402 | " std::cout << work->iter << std::endl;\n", 403 | " std::cout << work->u.col(0).transpose().format(CleanFmt) << std::endl;\n", 404 | "\n", 405 | " // 5. Simulate forward\n", 406 | " // work->u.col(0) = -tiny_data_solver.cache->Kinf * (x0 - work->Xref.col(0));\n", 407 | " x1 = work->Adyn * x0 + work->Bdyn * work->u.col(0);\n", 408 | " x0 = x1;\n", 409 | " // std::cout << x0.transpose().format(CleanFmt) << std::endl;\n", 410 | " }\n", 411 | "}\n", 412 | "```" 413 | ] 414 | } 415 | ], 416 | "metadata": { 417 | "kernelspec": { 418 | "display_name": "Julia 1.6.7", 419 | "language": "julia", 420 | "name": "julia-1.6" 421 | }, 422 | "language_info": { 423 | "file_extension": ".jl", 424 | "mimetype": "application/julia", 425 | "name": "julia", 426 | "version": "1.6.7" 427 | }, 428 | "orig_nbformat": 4 429 | }, 430 | "nbformat": 4, 431 | "nbformat_minor": 2 432 | } 433 | -------------------------------------------------------------------------------- /examples/interactive_safety_filter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Python Interactive Example: TinyMPC-Based Predictive Safety Filter on Double Integrator\n", 9 | "\n", 10 | "In this demonstration, we showcase an interactive Python workflow using TinyMPC for safety filter. You can generate C++ code and engage with it seamlessly within the Python environment.\n", 11 | "\n", 12 | "If any issues arise, restart the kernel." 13 | ] 14 | }, 15 | { 16 | "attachments": {}, 17 | "cell_type": "markdown", 18 | "metadata": {}, 19 | "source": [ 20 | "Load necessary packages, make sure to install `tinympc` ([README.md](../README.md))" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 221, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import Pkg;\n", 30 | "Pkg.activate(@__DIR__);\n", 31 | "Pkg.instantiate()\n", 32 | "\n", 33 | "using Libdl\n", 34 | "using Random\n", 35 | "using PyPlot\n", 36 | "using LinearAlgebra\n", 37 | "\n", 38 | "include(joinpath(@__DIR__,\"../tinympc/TinyMPC.jl\"))\n", 39 | "using .TinyMPC\n", 40 | "include(\"visualization.jl\") # for visualization" 41 | ] 42 | }, 43 | { 44 | "attachments": {}, 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "## Double Integrator System" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 222, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "data": { 58 | "text/plain": [ 59 | "3×200 Matrix{Float64}:\n", 60 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 61 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 62 | " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0" 63 | ] 64 | }, 65 | "metadata": {}, 66 | "output_type": "display_data" 67 | } 68 | ], 69 | "source": [ 70 | "NSTATES = 6\n", 71 | "NINPUTS = 3\n", 72 | "NHORIZON = 30\n", 73 | "NTOTAL = 201\n", 74 | "\n", 75 | "# Double-integrator dynamics\n", 76 | "h = 0.05 #20 Hz\n", 77 | "temp_n = Int(NSTATES/2)\n", 78 | "Adyn = [I(temp_n) h*I(temp_n); zeros(temp_n,temp_n) I(temp_n)]\n", 79 | "Bdyn = [0.5*h*h*I(temp_n); h*I(temp_n)];\n", 80 | "\n", 81 | "t = h*(0:NTOTAL-1)\n", 82 | "Xref = zeros(NSTATES, NTOTAL)\n", 83 | "for k = 1:NTOTAL\n", 84 | " Xref[1:3,k] = sin(1*t[k])*2*ones(temp_n)\n", 85 | "end\n", 86 | "Uref = repeat([0; 0; 0.0], 1, NTOTAL-1) \n" 87 | ] 88 | }, 89 | { 90 | "attachments": {}, 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "## Code Generation\n", 95 | "\n", 96 | "Now, let's define the class and compile original TinyMPC code to get a generic shared/dynamic library\n", 97 | "\n", 98 | "**PLEASE CHANGE `tinympc_julia_dir` TO YOUR ABSOLUTE PATH**" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 223, 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "name": "stdout", 108 | "output_type": "stream", 109 | "text": [ 110 | "Compiling library to /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC\n", 111 | "-- Configuring done\n" 112 | ] 113 | }, 114 | { 115 | "name": "stdout", 116 | "output_type": "stream", 117 | "text": [ 118 | "-- Generating done\n", 119 | "-- Build files have been written to: /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/build\n" 120 | ] 121 | }, 122 | { 123 | "name": "stdout", 124 | "output_type": "stream", 125 | "text": [ 126 | "Consolidate compiler generated dependencies of target tinympcShared\n", 127 | "[ 18%] Built target tinympcShared\n" 128 | ] 129 | }, 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "Consolidate compiler generated dependencies of target tinympc\n", 135 | "[ 37%] Built target tinympc\n" 136 | ] 137 | }, 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "Consolidate compiler generated dependencies of target codegen_cartpole\n", 143 | "[ 50%] Built target codegen_cartpole\n" 144 | ] 145 | }, 146 | { 147 | "name": "stdout", 148 | "output_type": "stream", 149 | "text": [ 150 | "Consolidate compiler generated dependencies of target codegen_random\n", 151 | "[ 62%] Built target codegen_random\n" 152 | ] 153 | }, 154 | { 155 | "name": "stdout", 156 | "output_type": "stream", 157 | "text": [ 158 | "Consolidate compiler generated dependencies of target quadrotor_hovering\n", 159 | "[ 75%] Built target quadrotor_hovering\n" 160 | ] 161 | }, 162 | { 163 | "name": "stdout", 164 | "output_type": "stream", 165 | "text": [ 166 | "Consolidate compiler generated dependencies of target quadrotor_tracking\n", 167 | "[ 87%] Built target quadrotor_tracking\n", 168 | "Consolidate compiler generated dependencies of target test1\n", 169 | "[100%] Built target test1\n" 170 | ] 171 | }, 172 | { 173 | "data": { 174 | "text/plain": [ 175 | "true" 176 | ] 177 | }, 178 | "metadata": {}, 179 | "output_type": "display_data" 180 | } 181 | ], 182 | "source": [ 183 | "tinympc_julia_dir = \"/home/khai/SSD/Code/tinympc-julia\" # Your absolute path to the tinympc-Julia directory, you need to change this\n", 184 | "tinympc_dir = tinympc_julia_dir * \"/tinympc/TinyMPC\" # Path to the TinyMPC directory (C code)\n", 185 | "TinyMPC.compile_lib(tinympc_dir) # Compile the C code into a shared library" 186 | ] 187 | }, 188 | { 189 | "attachments": {}, 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "Load the generic shared/dynamic library. **You may want to change the extension of the library based on your OS -- Linux: .so, Mac: .dylib, Windows: .dll**" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 224, 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "data": { 203 | "text/plain": [ 204 | "\"/home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/build/src/tinympc/libtinympcShared.so\"" 205 | ] 206 | }, 207 | "metadata": {}, 208 | "output_type": "display_data" 209 | } 210 | ], 211 | "source": [ 212 | "os_ext = \".so\" # CHANGE THIS BASED ON YOUR OS\n", 213 | "tinympc = tinympc_dir * \"/build/src/tinympc/libtinympcShared\" * os_ext # Path to the compiled library" 214 | ] 215 | }, 216 | { 217 | "attachments": {}, 218 | "cell_type": "markdown", 219 | "metadata": {}, 220 | "source": [ 221 | "Here we setup problem data and settings for TinyMPC" 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "execution_count": 225, 227 | "metadata": {}, 228 | "outputs": [ 229 | { 230 | "data": { 231 | "text/plain": [ 232 | "1×36 adjoint(::Vector{Float64}) with eltype Float64:\n", 233 | " 1.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.05 0.0 0.0 1.0" 234 | ] 235 | }, 236 | "metadata": {}, 237 | "output_type": "display_data" 238 | }, 239 | { 240 | "data": { 241 | "text/plain": [ 242 | "1×18 adjoint(::Vector{Float64}) with eltype Float64:\n", 243 | " 0.00125 0.0 0.0 0.05 0.0 0.0 0.0 … 0.0 0.0 0.00125 0.0 0.0 0.05" 244 | ] 245 | }, 246 | "metadata": {}, 247 | "output_type": "display_data" 248 | }, 249 | { 250 | "data": { 251 | "text/plain": [ 252 | "1" 253 | ] 254 | }, 255 | "metadata": {}, 256 | "output_type": "display_data" 257 | } 258 | ], 259 | "source": [ 260 | "# convert A to array column major\n", 261 | "Acol = cat(Adyn..., dims=2)[:]\n", 262 | "Bcol = cat(Bdyn..., dims=2)[:]\n", 263 | "display(Acol')\n", 264 | "display(Bcol')\n", 265 | "Q = zeros(NSTATES) # dont need to penalize the state in safety fitler\n", 266 | "R = 1e2*ones(NINPUTS)\n", 267 | "rho = 5e2\n", 268 | "\n", 269 | "###### Bounds\n", 270 | "xmin = -1. * ones(NSTATES*NHORIZON) # state constraints\n", 271 | "xmax = 1. * ones(NSTATES*NHORIZON) # state constraints\n", 272 | "umin = -3 * ones(NINPUTS*(NHORIZON-1)) # force constraints\n", 273 | "umax = 3 * ones(NINPUTS*(NHORIZON-1)) # force constraints\n", 274 | "\n", 275 | "##### Settings\n", 276 | "abs_pri_tol = 1e-2\n", 277 | "abs_dua_tol = 1e-2\n", 278 | "max_iter = 50\n", 279 | "check_termination = 1" 280 | ] 281 | }, 282 | { 283 | "attachments": {}, 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "After define the problem, we generate the tailored code with above data. \n", 288 | "\n", 289 | "**Here we compile it for interactive Julia script but you can use it directly for your applications/systems**\n", 290 | "\n", 291 | "Since Julia does JIT compilation, we cannot wrap C functions now -- we haven't generated the C code yet!. Therefore, we need to call the C function using `ccall` directly, which doesn't look nice :(" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 226, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "name": "stdout", 301 | "output_type": "stream", 302 | "text": [ 303 | "A = [ 1, 0, 0, 0.05, 0, 0]\n", 304 | "[ 0, 1, 0, 0, 0.05, 0]\n", 305 | "[ 0, 0, 1, 0, 0, 0.05]\n", 306 | "[ 0, 0, 0, 1, 0, 0]\n", 307 | "[ 0, 0, 0, 0, 1, 0]\n", 308 | "[ 0, 0, 0, 0, 0, 1]\n", 309 | "B = [0.00125, 0, 0]\n", 310 | "[ 0, 0.00125, 0]\n", 311 | "[ 0, 0, 0.00125]\n", 312 | "[ 0.05, 0, 0]\n", 313 | "[ 0, 0.05, 0]\n", 314 | "[ 0, 0, 0.05]\n", 315 | "Q = [500, 0, 0, 0, 0, 0]\n", 316 | "[ 0, 500, 0, 0, 0, 0]\n", 317 | "[ 0, 0, 500, 0, 0, 0]\n", 318 | "[ 0, 0, 0, 500, 0, 0]\n", 319 | "[ 0, 0, 0, 0, 500, 0]\n", 320 | "[ 0, 0, 0, 0, 0, 500]\n", 321 | "R = [600, 0, 0]\n", 322 | "[ 0, 600, 0]\n", 323 | "[ 0, 0, 600]\n", 324 | "rho = 500\n", 325 | "Kinf converged after 134 iterations\n", 326 | "Precomputing finished\n", 327 | "Kinf = [0.8763, 0, 0, 1.588, 0, 0]\n", 328 | "[ 0, 0.8763, 0, 0, 1.588, 0]\n", 329 | "[ 0, 0, 0.8763, 0, 0, 1.588]\n", 330 | "Pinf = [1.812e+04, 0, 0, 1.096e+04, 0, 0]\n", 331 | "[ 0, 1.812e+04, 0, 0, 1.096e+04, 0]\n", 332 | "[ 0, 0, 1.812e+04, 0, 0, 1.096e+04]\n", 333 | "[1.096e+04, 0, 0, 1.983e+04, 0, 0]\n", 334 | "[ 0, 1.096e+04, 0, 0, 1.983e+04, 0]\n", 335 | "[ 0, 0, 1.096e+04, 0, 0, 1.983e+04]\n", 336 | "Quu_inv = [0.001536, 0, 0]\n", 337 | "[ 0, 0.001536, 0]\n", 338 | "[ 0, 0, 0.001536]\n", 339 | "AmBKt = [ 0.9989, 0, 0, -0.04382, 0, 0]\n", 340 | "[ 0, 0.9989, 0, 0, -0.04382, 0]\n", 341 | "[ 0, 0, 0.9989, 0, 0, -0.04382]\n", 342 | "[ 0.04802, 0, 0, 0.9206, 0, 0]\n", 343 | "[ 0, 0.04802, 0, 0, 0.9206, 0]\n", 344 | "[ 0, 0, 0.04802, 0, 0, 0.9206]\n", 345 | "Data generated in /home/khai/SSD/Code/tinympc-julia/generated_code1/src/tiny_data_workspace.cpp\n", 346 | "Global options generated in /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/glob_opts.hpp\n", 347 | "Example tinympc main generated in /home/khai/SSD/Code/tinympc-julia/generated_code1/src/tiny_main.cpp\n", 348 | "Data header generated in /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/tiny_data_workspace.hpp\n", 349 | "Content of include folder copied from /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/include to /home/khai/SSD/Code/tinympc-julia/generated_code1/include\n", 350 | "Content of /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/src/tinympc/admm.hpp copied to /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/admm.hpp\n", 351 | "Content of /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/src/tinympc/admm.cpp copied to /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/admm.cpp\n", 352 | "Content of /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/src/tinympc/types.hpp copied to /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/types.hpp\n", 353 | "Content of /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/src/tinympc/tiny_wrapper.hpp copied to /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/tiny_wrapper.hpp\n", 354 | "Content of /home/khai/SSD/Code/tinympc-julia/tinympc/TinyMPC/src/tinympc/tiny_wrapper.cpp copied to /home/khai/SSD/Code/tinympc-julia/generated_code1/tinympc/tiny_wrapper.cpp\n" 355 | ] 356 | }, 357 | { 358 | "data": { 359 | "text/plain": [ 360 | "1" 361 | ] 362 | }, 363 | "metadata": {}, 364 | "output_type": "display_data" 365 | } 366 | ], 367 | "source": [ 368 | "output_dir = tinympc_julia_dir * \"/generated_code1\" # Path to the generated code\n", 369 | "\n", 370 | "@ccall tinympc.tiny_codegen(NSTATES::Cint, NINPUTS::Cint, NHORIZON::Cint, Acol::Ptr{Float64}, Bcol::Ptr{Float64}, Q::Ptr{Float64}, R::Ptr{Float64}, xmin::Ptr{Float64}, xmax::Ptr{Float64}, umin::Ptr{Float64}, umax::Ptr{Float64}, rho::Float64, abs_pri_tol::Float64, abs_dua_tol::Float64, max_iter::Cint, check_termination::Cint, 1::Cint, tinympc_dir::Ptr{UInt8}, output_dir::Ptr{UInt8})::Cint\n", 371 | "\n", 372 | "TinyMPC.compile_lib(output_dir)" 373 | ] 374 | }, 375 | { 376 | "attachments": {}, 377 | "cell_type": "markdown", 378 | "metadata": {}, 379 | "source": [ 380 | "## Interactive Program (WIP)\n", 381 | "\n", 382 | "Run the interactive example which calls the generated code.\n", 383 | "\n", 384 | "Since this works with pointers, underlying data is persistent in each kernel session (something like deepcopy/shallowcopy or pass by reference/value). If you want to run from the original setup, you may need to change data back or \n", 385 | "restart kernel." 386 | ] 387 | }, 388 | { 389 | "attachments": {}, 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "### Nominal Controller" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 228, 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "text/plain": [ 404 | "rollout! (generic function with 1 method)" 405 | ] 406 | }, 407 | "metadata": {}, 408 | "output_type": "display_data" 409 | } 410 | ], 411 | "source": [ 412 | "Knom = [4.77182 0.0 0.0 5.68453 0.0 0.0;\n", 413 | " 0.0 4.77182 0.0 0.0 5.68453 0.0;\n", 414 | " 0.0 0.0 4.77182 0.0 0.0 5.68453] # nominal gain\n", 415 | "\n", 416 | "# rollout the closed-loop system to get future control inputs\n", 417 | "function rollout!(Upred, x, Xref_hrz, integral) \n", 418 | " xn = x*1\n", 419 | " for k = 1:NHORIZON-1\n", 420 | " integral += (Xref_hrz[1:3,k] - xn[1:3])\n", 421 | " # Upred[:,k] = -1*Knom*(xn - Xref_hrz[:,k]) + 20.0*integral\n", 422 | " Upred[:,k] = [-4.0; 4.0; -4.0] # constant control input\n", 423 | " xn = Adyn*xn + Bdyn*Upred[:,k]\n", 424 | " end\n", 425 | "end" 426 | ] 427 | }, 428 | { 429 | "attachments": {}, 430 | "cell_type": "markdown", 431 | "metadata": {}, 432 | "source": [ 433 | "### TinyMPC-based Safety Filter" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 229, 439 | "metadata": {}, 440 | "outputs": [ 441 | { 442 | "data": { 443 | "text/plain": [ 444 | "3×29 Matrix{Float64}:\n", 445 | " -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 … -4.0 -4.0 -4.0 -4.0 -4.0 -4.0\n", 446 | " 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0\n", 447 | " -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0 -4.0" 448 | ] 449 | }, 450 | "metadata": {}, 451 | "output_type": "display_data" 452 | }, 453 | { 454 | "name": "stdout", 455 | "output_type": "stream", 456 | "text": [ 457 | "set_x0 result: 0.000000\n", 458 | "set_x0 result: 0.000000\n", 459 | "set_x0 result: 0.000000\n", 460 | "set_x0 result: 0.000000\n", 461 | "set_x0 result: 0.000000\n", 462 | "set_x0 result: 0.000000\n", 463 | "set_xref result: -4.000000\n", 464 | "set_xref result: 4.000000\n", 465 | "set_xref result: -4.000000\n", 466 | "set_xref result: -4.000000\n", 467 | "set_xref result: 4.000000\n", 468 | "set_xref result: -4.000000\n", 469 | "set_xref result: -4.000000\n", 470 | "set_xref result: 4.000000\n", 471 | "set_xref result: -4.000000\n", 472 | "set_xref result: -4.000000\n", 473 | "set_xref result: 4.000000\n", 474 | "set_xref result: -4.000000\n", 475 | "set_xref result: -4.000000\n", 476 | "set_xref result: 4.000000\n", 477 | "set_xref result: -4.000000\n", 478 | "set_xref result: -4.000000\n", 479 | "set_xref result: 4.000000\n", 480 | "set_xref result: -4.000000\n", 481 | "set_xref result: -4.000000\n", 482 | "set_xref result: 4.000000\n", 483 | "set_xref result: -4.000000\n", 484 | "set_xref result: -4.000000\n", 485 | "set_xref result: 4.000000\n", 486 | "set_xref result: -4.000000\n", 487 | "set_xref result: -4.000000\n", 488 | "set_xref result: 4.000000\n", 489 | "set_xref result: -4.000000\n", 490 | "set_xref result: -4.000000\n", 491 | "set_xref result: 4.000000\n", 492 | "set_xref result: -4.000000\n", 493 | "set_xref result: -4.000000\n", 494 | "set_xref result: 4.000000\n", 495 | "set_xref result: -4.000000\n", 496 | "set_xref result: -4.000000\n", 497 | "set_xref result: 4.000000\n", 498 | "set_xref result: -4.000000\n", 499 | "set_xref result: -4.000000\n", 500 | "set_xref result: 4.000000\n", 501 | "set_xref result: -4.000000\n", 502 | "set_xref result: -4.000000\n", 503 | "set_xref result: 4.000000\n", 504 | "set_xref result: -4.000000\n", 505 | "set_xref result: -4.000000\n", 506 | "set_xref result: 4.000000\n", 507 | "set_xref result: -4.000000\n", 508 | "set_xref result: -4.000000\n", 509 | "set_xref result: 4.000000\n", 510 | "set_xref result: -4.000000\n", 511 | "set_xref result: -4.000000\n", 512 | "set_xref result: 4.000000\n", 513 | "set_xref result: -4.000000\n", 514 | "set_xref result: -4.000000\n", 515 | "set_xref result: 4.000000\n", 516 | "set_xref result: -4.000000\n", 517 | "set_xref result: -4.000000\n", 518 | "set_xref result: 4.000000\n", 519 | "set_xref result: -4.000000\n", 520 | "set_xref result: -4.000000\n", 521 | "set_xref result: 4.000000\n", 522 | "set_xref result: -4.000000\n", 523 | "set_xref result: -4.000000\n", 524 | "set_xref result: 4.000000\n", 525 | "set_xref result: -4.000000\n", 526 | "set_xref result: -4.000000\n", 527 | "set_xref result: 4.000000\n", 528 | "set_xref result: -4.000000\n", 529 | "set_xref result: -4.000000\n", 530 | "set_xref result: 4.000000\n", 531 | "set_xref result: -4.000000\n", 532 | "set_xref result: -4.000000\n", 533 | "set_xref result: 4.000000\n", 534 | "set_xref result: -4.000000\n", 535 | "set_xref result: -4.000000\n", 536 | "set_xref result: 4.000000\n", 537 | "set_xref result: -4.000000\n", 538 | "set_xref result: -4.000000\n", 539 | "set_xref result: 4.000000\n", 540 | "set_xref result: -4.000000\n", 541 | "set_xref result: -4.000000\n", 542 | "set_xref result: 4.000000\n", 543 | "set_xref result: -4.000000\n", 544 | "set_xref result: -4.000000\n", 545 | "set_xref result: 4.000000\n", 546 | "set_xref result: -4.000000\n", 547 | "set_xref result: -4.000000\n", 548 | "set_xref result: 4.000000\n", 549 | "set_xref result: -4.000000\n", 550 | "u_soln: -nan\n", 551 | "u_soln: -nan\n", 552 | "u_soln: -nan\n", 553 | "u_soln: nan\n", 554 | "u_soln: nan\n", 555 | "u_soln: nan\n", 556 | "u_soln: -nan\n", 557 | "u_soln: -nan\n", 558 | "u_soln: -nan\n", 559 | "u_soln: nan\n", 560 | "u_soln: nan\n", 561 | "u_soln: nan\n", 562 | "u_soln: -nan\n", 563 | "u_soln: -nan\n", 564 | "u_soln: -nan\n", 565 | "u_soln: nan\n", 566 | "u_soln: nan\n", 567 | "u_soln: nan\n", 568 | "u_soln: -nan\n", 569 | "u_soln: -nan\n", 570 | "u_soln: -nan\n", 571 | "u_soln: nan\n", 572 | "u_soln: nan\n", 573 | "u_soln: nan\n", 574 | "u_soln: -nan\n", 575 | "u_soln: -nan\n", 576 | "u_soln: -nan\n", 577 | "u_soln: nan\n", 578 | "u_soln: nan\n" 579 | ] 580 | } 581 | ], 582 | "source": [ 583 | "# Control loop\n", 584 | "en_safety_filter = 1 # ENABLE SAFETY FILTER OR NOT\n", 585 | "\n", 586 | "tinympc = output_dir * \"/build/tinympc/libtinympcShared\" * os_ext # Path to the compiled library\n", 587 | "u = Array{Float32}(zeros(NINPUTS*(NHORIZON-1))) # List of control inputs in horizon\n", 588 | "Random.seed!(1234)\n", 589 | "Xhist = zeros(NSTATES, NTOTAL)\n", 590 | "x0 = zeros(NSTATES)\n", 591 | "Xhist[:,1] .= x0 + randn(NSTATES)*0\n", 592 | "Uhist = zeros(NINPUTS, NTOTAL-1)\n", 593 | "Upred = zeros(NINPUTS, NHORIZON-1)\n", 594 | "integral = zeros(NINPUTS)\n", 595 | "\n", 596 | "NRUNS = NTOTAL-NHORIZON-1 \n", 597 | "for i = 1:1\n", 598 | " # i%10 == 0 && print(\"i = \", i, \"\\n\")\n", 599 | " # Get measurements\n", 600 | " pos_norm = norm(Xhist[1:3, i], Inf) / 1e2 # 1% noise\n", 601 | " vel_norm = norm(Xhist[4:6, i], Inf) / 1e4 # 1ppm noise\n", 602 | " noise_pos = randn(3)\n", 603 | " noise_vel = randn(3)\n", 604 | " xk = Xhist[:,i] + 0*[noise_pos * pos_norm; noise_vel * vel_norm]\n", 605 | " \n", 606 | " # Nominal control rollout\n", 607 | " rollout!(Upred, xk, Xref[:,i:i+NHORIZON-1], integral)\n", 608 | " Uhist[:,i] .= Upred[:,1]\n", 609 | " display(Upred)\n", 610 | " \n", 611 | " # Solve safety filter\n", 612 | " if en_safety_filter == 1\n", 613 | " xk = Array{Float32}(xk)\n", 614 | " @ccall tinympc.set_x0(xk::Ptr{Float32}, 1::Cint)::Cvoid\n", 615 | "\n", 616 | " Upred_ = Array{Float32}(Upred) # col-major array\n", 617 | " # print(Upred_, \"\\n\")\n", 618 | " @ccall tinympc.set_uref(Upred_::Ptr{Float32}, 1::Cint)::Cvoid\n", 619 | "\n", 620 | " @ccall tinympc.call_tiny_solve(0::Cint)::Cvoid\n", 621 | "\n", 622 | " # Get the control input\n", 623 | " @ccall tinympc.get_u(u::Ptr{Float32}, 1::Cint)::Cvoid\n", 624 | " # println(u)\n", 625 | " # Uhist[:,i] .= u[0:NINPUTS]\n", 626 | " end\n", 627 | "\n", 628 | " # Clamp control input\n", 629 | " # Uhist[:,i] = max.(min.(Uhist[:,i], umax[:,1]), umin[:,1])\n", 630 | "\n", 631 | " # print(Upred, \"\\n\")\n", 632 | " # print(solver.workspace.u, \"\\n\")\n", 633 | " # print(solver.workspace.x, \"\\n\")\n", 634 | "\n", 635 | " # Simulate\n", 636 | " Xhist[:,i+1] .= Adyn*Xhist[:,i] + Bdyn*Uhist[:,i]\n", 637 | "end" 638 | ] 639 | }, 640 | { 641 | "cell_type": "code", 642 | "execution_count": 230, 643 | "metadata": {}, 644 | "outputs": [ 645 | { 646 | "data": { 647 | "image/png": "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Zo2mTZuWjmn6HA4o9KAAANwxcuRIVVVVacKECcrNzdXcuXOVkZGRtM2NN96o8ePHKx6Pq6ysLE0zPcbhgMISDwDAHRUVFaqurtb48eMViUR07733JlVQJGn06NHKz8/Xueeeq4KCNDX+NnI4oGQe+5OAAgBwQE5OjpYsWZL02NerJIcPH9b//d//afr06amc2nE5HFCooAAAIEmJREKfffaZfvnLXyo3N1cTJ05M95RcDij0oAAAIEk7d+5USUmJCgsLVVVVpU6d0h8P0j+DdKGCAgCApGOXwf/6R5DTjQu1EVAAALAOAYWAAgCAdRwOKPSgAABgK4cDChUUAABsRUAhoAAAYB0CCgEFAADrBBpQFi1apMGDBysnJ0c5OTkaPny4Xn755SCHbD2/B4WAAgCAbQINKIWFhVqwYIE2btyoDRs2aOTIkbrqqqv017/+NchhW8evoNAkCwCAbQK9UNuECROS7t93331atGiR1q5dq3PPPTfIoU+uKaDE69M7DwAA0ELKelDi8biWLFmiw4cPa/jw4cfdJhaLKRqNJt0CQw8KAMAh/fv318KFC5MeGzp0qObPn6+qqip5ntfiNn/+/LTMVUrBpe7ff/99DR8+XEePHlW3bt20dOlSnXPOOcfdtrKyUnfffXfQUzqGHhQAQAcwxujLhi/TMnaXTl3ked4pv86kSZM0duxY//7KlSt1/fXX69JLLz3l126vwAPKoEGDtHnzZtXW1uqFF15QWVmZVq1addyQUlFRoVmzZvn3o9GoioqKgpkYPSgAgA7wZcOXKn22NC1jr/vxOmVnZp/y63Tp0kVdunSRJO3YsUPl5eW6//779fd///en/NrtFXhAycrK0plnnilJGjZsmNavX69/+7d/0+OPP95i23A4rHA4HPSUjsnIPPYnFRQAACRJtbW1Gj9+vK688krdeeedaZ1Lyr/NOJFIKBaLpXrYluhBAQB0gC6dumjdj9elbezWCoVCLb6xuL6++YMi8XhckyZNUk5Ojp544okOm2N7BRpQKioqNG7cOBUXF+vQoUN69tlntXLlSr3yyitBDts69KAAADqA53kdsswStLy8PNXU1Pj3o9Goqqur/fu333673n//fW3YsEGdO3dOxxSTBBpQ9u3bpylTpqimpkaRSESDBw/WK6+8ktY1LR89KAAAh4wcOVJVVVWaMGGCcnNzNXfuXGVkHPuf9cWLF+s//uM/tHTpUnmepz179kiSunXrpm7duqVlvoEGlCeffDLIlz81LPEAABxSUVGh6upqjR8/XpFIRPfee69fQVm1apXi8bgmTpyY9Dvz5s1L20eNU96DYg0CCgDAITk5OVqyZEnSY2VlZf7PVVVVKZ7RiTn8ZYH0oAAAYCuHAwo9KAAA2IqAQgUFAADrEFAIKAAAWIeAQkABAMA6DgcUmmQBAO3z9SuyuijofeBwQKGCAgBom8zMY9/jduTIkTTPJP3q6uokyb/YW0fjOigEFABAK2VkZCg3N1f79u2TJGVnZ8vzvDTPKvUSiYT279+v7OxsdeoUTJQgoBBQAABt0LdvX0nyQ4qrQqGQiouLAwtoBBSugwIAaAPP85Sfn6/evXsnfRuwa7KyshQKBdcpQkChggIAaIeMjIzA+i9AkywBBQAACxFQCCgAAFjH4YDCdVAAALCVwwGFJlkAAGxFQKGCAgCAdQgoBBQAAKxDQCGgAABgHYcDSlOTLD0oAADYxuGAQgUFAABbEVAIKAAAWIeAEiegAABgG4cDChdqAwDAVg4HFJZ4AACwFQGFgAIAgHXcDSgZmcf+NHHJmPTOBQAAJHE3oDT1oEhcCwUAAMs4HFA6Nf/MMg8AAFYhoEgEFAAALENAkQgoAABYJtCAUllZqe9973vq3r27evfurauvvlrbtm0LcsjW8+hBAQDAVoEGlFWrVqm8vFxr167VihUrVF9fryuuuEKHDx8OctjWCYUkr/HtU0EBAMAqnU6+Sfv96U9/SrpfVVWl3r17a+PGjbrsssuCHLp1Qp2keB0BBQAAywQaUL6utrZWktSjR4/jPh+LxRSLxfz70Wg02AkRUAAAsFLKmmQTiYRuu+02XXrppTrvvPOOu01lZaUikYh/KyoqCnZSXE0WAAArpSyglJeXa8uWLVqyZMk3blNRUaHa2lr/tmvXrmAn5X9hIE2yAADYJCVLPDNnztTy5cu1evVqFRYWfuN24XBY4XA4FVM6xq+g1KduTAAAcFKBBhRjjH76059q6dKlWrlypUpKSoIcru1Y4gEAwEqBBpTy8nI9++yzWrZsmbp37649e/ZIkiKRiLp06RLk0K1DQAEAwEqB9qAsWrRItbW1GjFihPLz8/3bc889F+SwrUcPCgAAVgp8icdqVFAAALCSu9/FI0mhzGN/ElAAALCK4wGFCgoAADZyPKDQgwIAgI0cDyhUUAAAsBEBRSKgAABgGQKKREABAMAyjgcUelAAALCR4wGFCgoAADYioEgEFAAALENAkQgoAABYxvGA0tSDQkABAMAmjgeUxgpKnIACAIBNCCgSFRQAACxDQJEIKAAAWMbxgEIPCgAANnI7oGRkHvuTC7UBAGAVtwMKSzwAAFiJgCIRUAAAsIzjAYUeFAAAbOR4QGmqoNCDAgCATQgoEhUUAAAsQ0CRCCgAAFjG8YBCDwoAADZyPKDQgwIAgI0IKBIVFAAALENAkQgoAABYhoAiSYn69M4DAAAkcTygNDXJ0oMCAIBNHA8oLPEAAGAjAopEQAEAwDIEFImAAgCAZQINKKtXr9aECRNUUFAgz/P00ksvBTlc23EdFAAArBRoQDl8+LCGDBmixx57LMhh2o8KCgAAVuoU5IuPGzdO48aNC3KIU0NAAQDASoEGlLaKxWKKxWL+/Wg0GuyABBQAAKxkVZNsZWWlIpGIfysqKgp2QL4sEAAAK1kVUCoqKlRbW+vfdu3aFeyANMkCAGAlq5Z4wuGwwuFw6gZkiQcAACtZVUFJOQIKAABWCrSC8sUXX2j79u3+/erqam3evFk9evRQcXFxkEO3DgEFAAArBRpQNmzYoMsvv9y/P2vWLElSWVmZqqqqghy6dfiyQAAArBRoQBkxYoSMMUEOcWqaKijx+vTOAwAAJKEHRWKJBwAAyxBQJJZ4AACwjOMBhQu1AQBgI8cDCks8AADYiIAiEVAAALCM2wElI/PYnyYu2fxpIwAAHON2QGnqQZFolAUAwCKOB5SvXAaGZR4AAKxBQGlCQAEAwBoElCYEFAAArOF2QPHoQQEAwEZuB5RQSPIadwEVFAAArOF2QJG4FgoAABYioBBQAACwDgGFgAIAgHUIKHxhIAAA1iGgUEEBAMA6BBQCCgAA1iGgEFAAALAOAcXvQeFCbQAA2IKAEso89icVFAAArEFAYYkHAADrEFAIKAAAWIeAQg8KAADWIaBQQQEAwDoEFAIKAADWIaAQUAAAsA4BhR4UAACsQ0ChggIAgHUIKAQUAACsQ0BpCijx+vTOAwAA+FISUB577DH1799fnTt3Vmlpqd55551UDNs6fg8KFRQAAGwReEB57rnnNGvWLM2bN0+bNm3SkCFDNGbMGO3bty/ooVvHX+KhSRYAAFsEHlAefvhhzZgxQ9OmTdM555yjX//618rOztZTTz0V9NCtQw8KAADW6RTki9fV1Wnjxo2qqKjwHwuFQho9erTWrFnTYvtYLKZYLObfj0ajQU5PklRdH9OyMyL67C+L9cUHywIfDwAAm+Rn99PsH/+/dE+jhUADymeffaZ4PK4+ffokPd6nTx9t3bq1xfaVlZW6++67g5xSCwu/qNHruRFJdZL2pHRsAADSbfChA+mewnEFGlDaqqKiQrNmzfLvR6NRFRUVBTrmjqxiyexRSV2Ozs44I9CxAACwTd/c/umewnEFGlB69eqljIwM7d27N+nxvXv3qm/fvi22D4fDCofDQU6phZjXSTJSYd8f6oEJt6d0bAAAcHyBNslmZWVp2LBheu211/zHEomEXnvtNQ0fPjzIoVstbo59eqdTyKpiEgAATgv8rDxr1iyVlZXpoosu0sUXX6yFCxfq8OHDmjZtWtBDt0qCgAIAgHUCPytPmjRJ+/fv19y5c7Vnzx4NHTpUf/rTn1o0zqZLQk0BJSPNMwEAAE1SUjaYOXOmZs6cmYqh2ixh4pJHQAEAwCbOfxdPQglJUiZLPAAAWMP5gGIae1AyqKAAAGAN5wNKUw9KZigzzTMBAABNnA8oxtAkCwCAbZwPKH4PSgY9KAAA2ML5gGL8JR4qKAAA2ML5gNJ0oTYqKAAA2MP5gCK/gkJAAQDAFs4HFEMPCgAA1iGgUEEBAMA6BBQqKAAAWMf5gCKPS90DAGAb5wNK0xJP505cSRYAAFs4H1DEEg8AANYhoDQu8WQRUAAAsIbzAaVpiYeAAgCAPZwPKE1LPFmdCCgAANiCgMISDwAA1nE6oDTE4/I8I0nKyuBTPAAA2MLpgFKXaPB/JqAAAGAPtwNKQ3NACbPEAwCANZwOKLH4VyooNMkCAGANtwNKQ53/MxUUAADs4XhA+WoPCgEFAABbOB1Q6hqXeIwJKRRyelcAAGAVp8/KTQFFxundAACAdZw+Mzd/isfp3QAAgHWcPjPXxeslSZ7JSPNMAADAVzkdUOoTVFAAALCR02dmvwfF7d0AAIB1nD4z1zcGFE8s8QAAYJPAAsp9992nSy65RNnZ2crNzQ1qmFPifxcPn+IBAMAqgZ2Z6+rqdO211+qWW24JaohTRgUFAAA7BXb51LvvvluSVFVVFdQQp6w5oFBBAQDAJlZd3z0WiykWi/n3o9FooONRQQEAwE5WlQ4qKysViUT8W1FRUaDjNX3MmAoKAAB2adOZec6cOfI874S3rVu3tnsyFRUVqq2t9W+7du1q92u1Rn0iLknyPCooAADYpE1LPHfccYemTp16wm0GDBjQ7smEw2GFw+F2/35b1TU0XkmWCgoAAFZpU0DJy8tTXl5eUHNJuYbGJZ4QPSgAAFglsCbZnTt36sCBA9q5c6fi8bg2b94sSTrzzDPVrVu3oIZtE78HxaOCAgCATQILKHPnztXTTz/t37/gggskSW+88YZGjBgR1LBt0tDYg0IFBQAAuwRWOqiqqpIxpsXNlnAiNVdQQjTJAgBgFafXNvweFM+qy8EAAOA8xwNK0xKP07sBAADrOH1mbjCNAYUlHgAArOJ2QInTgwIAgI2cDijxxgpKBp/iAQDAKk4HFL8HhQoKAABWcTqgxM2xJZ6MEAEFAACbOB1QqKAAAGAnpwOKX0HhOigAAFjF7YDSWEHJoIICAIBV3A4ohoACAICNnA4oTZe6J6AAAGAXpwNKoqmCwqd4AACwitMBpXmJhyZZAABsQkCR1IkKCgAAVnE6oLDEAwCAnQgokjqxxAMAgFWcDijNSzwEFAAAbOJ0QEkQUAAAsJLbAUU0yQIAYCO3Awqf4gEAwEpuBxQlJEmZLPEAAGAVpwOK4WPGAABYyemA0tSDkhnKTPNMAADAVzkdUAw9KAAAWMnpgOL3oGTQgwIAgE2cDijGX+KhggIAgE2cDihNHzOmggIAgF2cDijyKygEFAAAbOJ0QDH0oAAAYCXHAwoVFAAAbBRYQPnoo480ffp0lZSUqEuXLho4cKDmzZunurq6oIZss6YKSrgT10EBAMAmgZUOtm7dqkQioccff1xnnnmmtmzZohkzZujw4cN66KGHghq2bTyWeAAAsFFgZ+axY8dq7Nix/v0BAwZo27ZtWrRokTUBpWmJJ4slHgAArJLSM3Ntba169Ojxjc/HYjHFYjH/fjQaDXhGVFAAALBRyppkt2/frkcffVQ/+clPvnGbyspKRSIR/1ZUVBTspBqXeLIIKAAAWKXNAWXOnDnyPO+Et61btyb9zqeffqqxY8fq2muv1YwZM77xtSsqKlRbW+vfdu3a1fZ31Ab+Eg8BBQAAq7T5zHzHHXdo6tSpJ9xmwIAB/s+7d+/W5ZdfrksuuURPPPHECX8vHA4rHA63dUqnoLGC0omAAgCATdp8Zs7Ly1NeXl6rtv300091+eWXa9iwYVq8eLFCIcsuu8ISDwAAVgrszPzpp59qxIgR6tevnx566CHt37/ff65v375BDdtqDfG4PM9IkrIyuA4KAAA2CSygrFixQtu3b9f27dtVWFiY9JwxJqhhW60u0eD/TEABAMAuga25TJ06VcaY495sUNfQHFDCLPEAAGAVy5pCUudoQ/Ml92mSBQDALs4GlLo4FRQAAGzlbECJNXy1B4WAAgCATZwNKE0VFGNC9n38GQAAxzl7ZvaXeIyzuwAAAGs5e3Zu/hRPRlrnAQAAWnI3oMTrJUkeFRQAAKzj7Nm53r9Qm7O7AAAAazl7dm7+mLGzuwAAAGs5e3aubwwoHj0oAABYx9mA4n8XDz0oAABYx9mzMxUUAADsRUBxdxcAAGAtZ8/OVFAAALCXuwElQQUFAABbOXt2rk/EJUmeRwUFAADbOBtQ6hoaryTr7i4AAMBazp6dGxqXeEL0oAAAYB1nA4rfg+I5uwsAALCWs2fnhsYeFCooAADYx9mA0lRBCXmd0jwTAADwdc4GFL8HhU/xAABgHYcDStMSj7O7AAAAazl7dm4wjQGFCgoAANZxN6DEWeIBAMBWzgaUeGMFJYNP8QAAYB1nA4rfg0IFBQAA6zgbUOLm2BJPRoiAAgCAbZwNKFRQAACwl7MBxa+gcKE2AACs425AaaygZFBBAQDAOoEGlIkTJ6q4uFidO3dWfn6+rr/+eu3evTvIIVutwa+gEFAAALBNoAHl8ssv1x/+8Adt27ZN//mf/6kdO3bohz/8YZBDthoVFAAA7BVoA8btt9/u/9yvXz/NmTNHV199terr65WZmRnk0CeVaLoOCp/iAQDAOinrED1w4ICeeeYZXXLJJd8YTmKxmGKxmH8/Go0GNh//Qm00yQIAYJ3Am2Rnz56trl27qmfPntq5c6eWLVv2jdtWVlYqEon4t6KiosDm1RRQOoUIKAAA2KbNAWXOnDnyPO+Et61bt/rb33nnnXr33Xf15z//WRkZGZoyZYqMMcd97YqKCtXW1vq3Xbt2tf+dnUTCDygs8QAAYJs2lw/uuOMOTZ069YTbDBgwwP+5V69e6tWrl77zne/ou9/9roqKirR27VoNHz68xe+Fw2GFw+G2Tqld/B4UmmQBALBOmwNKXl6e8vLy2jVYIpGQpKQ+k3RhiQcAAHsFdnZet26d1q9fr7/927/VGWecoR07duiuu+7SwIEDj1s9SbUEAQUAAGsF1iSbnZ2tF198UaNGjdKgQYM0ffp0DR48WKtWrUrZMs6JJEQPCgAAtgqsfHD++efr9ddfD+rlT1nCxCWPgAIAgI2c/S6ehI71w2SyxAMAgHWcDSiGK8kCAGAtZwNKUw9KZii9l9wHAAAtORtQDBdqAwDAWs4GFL8HJYMeFAAAbONsQDFqkCRlUkEBAMA6zgaUhKGCAgCArZwNKPKbZAkoAADYxtmAYhp7ULI68SkeAABs43BAoYICAICtHA4ojRUUelAAALCOswFFHk2yAADYytmA0rTEk8USDwAA1nE2oIgLtQEAYC13A4pHDwoAALZyNqD4SzwEFAAArONsQJF/HRQCCgAAtnE3oLDEAwCAtZwMKA3xuDzPSJKyMriSLAAAtnEyoNQlGvyfCSgAANjHzYDS0BxQwizxAABgHScDytGGOv9nmmQBALCPkwGlLk4FBQAAmzkZUGINX+1BIaAAAGAbJwNKUwXFmJBCISd3AQAAVnPy7Owv8Rgn3z4AANZz8gzd/CmejLTOAwAAHJ+bASVeL0nyqKAAAGAlJ8/Q9f6F2px8+wAAWM/JM3Tzx4ydfPsAAFjPyTN0fWNA8ehBAQDASikJKLFYTEOHDpXnedq8eXMqhjwh/7t46EEBAMBKKTlD/+xnP1NBQUEqhmoVKigAANgt8IDy8ssv689//rMeeuihoIdqteaAQgUFAAAbBXqd971792rGjBl66aWXlJ2dfdLtY7GYYrGYfz8ajQYyLyooAADYLbASgjFGU6dO1c0336yLLrqoVb9TWVmpSCTi34qKigKZW9PHjKmgAABgpzafoefMmSPP805427p1qx599FEdOnRIFRUVrX7tiooK1dbW+rddu3a1dXqtcl6fEp3f9Rp9P//KQF4fAACcGs8YY9ryC/v379fnn39+wm0GDBigH/3oR/rjH/8oz/P8x+PxuDIyMjR58mQ9/fTTJx0rGo0qEomotrZWOTk5bZkmAABIk444f7c5oLTWzp07k3pIdu/erTFjxuiFF15QaWmpCgsLT/oaBBQAAL59OuL8HViTbHFxcdL9bt26SZIGDhzYqnACAADcRZcoAACwTqAfM/6q/v37K6DVJAAAcJqhggIAAKxDQAEAANYhoAAAAOsQUAAAgHUIKAAAwDoEFAAAYB0CCgAAsA4BBQAAWIeAAgAArJOyK8m2R9OVZ7/6pYMAAMBuTeftU7mCvNUB5dChQ5KkoqKiNM8EAAC01aFDhxSJRNr1u56x+AtyEomEdu/ere7du8vzvA597Wg0qqKiIu3atavdXwV9OmA/NGNfNGNfNGNfHMN+aMa+aPZN+8IYo0OHDqmgoEChUPu6SayuoIRCIRUWFgY6Rk5OjvMHmMR++Cr2RTP2RTP2xTHsh2bsi2bH2xftrZw0oUkWAABYh4ACAACs42xACYfDmjdvnsLhcLqnklbsh2bsi2bsi2bsi2PYD83YF82C3BdWN8kCAAA3OVtBAQAA9iKgAAAA6xBQAACAdQgoAADAOk4GlMcee0z9+/dX586dVVpaqnfeeSfdUwpcZWWlvve976l79+7q3bu3rr76am3bti1pmxEjRsjzvKTbzTffnKYZB2P+/Pkt3uPZZ5/tP3/06FGVl5erZ8+e6tatm6655hrt3bs3jTMOTv/+/VvsC8/zVF5eLun0Ph5Wr16tCRMmqKCgQJ7n6aWXXkp63hijuXPnKj8/X126dNHo0aP14YcfJm1z4MABTZ48WTk5OcrNzdX06dP1xRdfpPBddIwT7Yv6+nrNnj1b559/vrp27aqCggJNmTJFu3fvTnqN4x1LCxYsSPE7OTUnOyamTp3a4j2OHTs2aRsXjglJx/13w/M8Pfjgg/42HXFMOBdQnnvuOc2aNUvz5s3Tpk2bNGTIEI0ZM0b79u1L99QCtWrVKpWXl2vt2rVasWKF6uvrdcUVV+jw4cNJ282YMUM1NTX+7YEHHkjTjINz7rnnJr3Ht956y3/u9ttv1x//+Ec9//zzWrVqlXbv3q0f/OAHaZxtcNavX5+0H1asWCFJuvbaa/1tTtfj4fDhwxoyZIgee+yx4z7/wAMP6N///d/161//WuvWrVPXrl01ZswYHT161N9m8uTJ+utf/6oVK1Zo+fLlWr16tW666aZUvYUOc6J9ceTIEW3atEl33XWXNm3apBdffFHbtm3TxIkTW2x7zz33JB0rP/3pT1Mx/Q5zsmNCksaOHZv0Hn//+98nPe/CMSEpaR/U1NToqaeekud5uuaaa5K2O+Vjwjjm4osvNuXl5f79eDxuCgoKTGVlZRpnlXr79u0zksyqVav8x/7u7/7O3HrrrembVArMmzfPDBky5LjPHTx40GRmZprnn3/ef+x//ud/jCSzZs2aFM0wfW699VYzcOBAk0gkjDFuHA/GGCPJLF261L+fSCRM3759zYMPPug/dvDgQRMOh83vf/97Y4wxH3zwgZFk1q9f72/z8ssvG8/zzKeffpqyuXe0r++L43nnnXeMJPPxxx/7j/Xr18888sgjwU4uhY63H8rKysxVV131jb/j8jFx1VVXmZEjRyY91hHHhFMVlLq6Om3cuFGjR4/2HwuFQho9erTWrFmTxpmlXm1trSSpR48eSY8/88wz6tWrl8477zxVVFToyJEj6ZheoD788EMVFBRowIABmjx5snbu3ClJ2rhxo+rr65OOj7PPPlvFxcWn/fFRV1en3/3ud7rhhhuSvpjThePh66qrq7Vnz56k4yASiai0tNQ/DtasWaPc3FxddNFF/jajR49WKBTSunXrUj7nVKqtrZXnecrNzU16fMGCBerZs6cuuOACPfjgg2poaEjPBAO0cuVK9e7dW4MGDdItt9yizz//3H/O1WNi7969+q//+i9Nnz69xXOnekxY/WWBHe2zzz5TPB5Xnz59kh7v06ePtm7dmqZZpV4ikdBtt92mSy+9VOedd57/+I9//GP169dPBQUFeu+99zR79mxt27ZNL774Yhpn27FKS0tVVVWlQYMGqaamRnfffbe+//3va8uWLdqzZ4+ysrJa/MPbp08f7dmzJz0TTpGXXnpJBw8e1NSpU/3HXDgejqfpv/Xx/p1oem7Pnj3q3bt30vOdOnVSjx49Tutj5ejRo5o9e7auu+66pC+G+5d/+RddeOGF6tGjh95++21VVFSopqZGDz/8cBpn27HGjh2rH/zgByopKdGOHTv085//XOPGjdOaNWuUkZHh7DHx9NNPq3v37i2WwjvimHAqoOCY8vJybdmyJan3QlLSWun555+v/Px8jRo1Sjt27NDAgQNTPc1AjBs3zv958ODBKi0tVb9+/fSHP/xBXbp0SePM0uvJJ5/UuHHjVFBQ4D/mwvGA1quvr9ePfvQjGWO0aNGipOdmzZrl/zx48GBlZWXpJz/5iSorK0+by8H/4z/+o//z+eefr8GDB2vgwIFauXKlRo0alcaZpddTTz2lyZMnq3PnzkmPd8Qx4dQST69evZSRkdHiUxl79+5V37590zSr1Jo5c6aWL1+uN954Q4WFhSfctrS0VJK0ffv2VEwtLXJzc/Wd73xH27dvV9++fVVXV6eDBw8mbXO6Hx8ff/yxXn31Vd14440n3M6F40GS/9/6RP9O9O3bt0VjfUNDgw4cOHBaHitN4eTjjz/WihUrkqonx1NaWqqGhgZ99NFHqZlgGgwYMEC9evXy/z64dkxI0ptvvqlt27ad9N8OqX3HhFMBJSsrS8OGDdNrr73mP5ZIJPTaa69p+PDhaZxZ8IwxmjlzppYuXarXX39dJSUlJ/2dzZs3S5Ly8/MDnl36fPHFF9qxY4fy8/M1bNgwZWZmJh0f27Zt086dO0/r42Px4sXq3bu3rrzyyhNu58LxIEklJSXq27dv0nEQjUa1bt06/zgYPny4Dh48qI0bN/rbvP7660okEn6QO100hZMPP/xQr776qnr27HnS39m8ebNCoVCLJY/TySeffKLPP//c//vg0jHR5Mknn9SwYcM0ZMiQk27brmPilFpsv4WWLFliwuGwqaqqMh988IG56aabTG5urtmzZ0+6pxaoW265xUQiEbNy5UpTU1Pj344cOWKMMWb79u3mnnvuMRs2bDDV1dVm2bJlZsCAAeayyy5L88w71h133GFWrlxpqqurzX//93+b0aNHm169epl9+/YZY4y5+eabTXFxsXn99dfNhg0bzPDhw83w4cPTPOvgxONxU1xcbGbPnp30+Ol+PBw6dMi8++675t133zWSzMMPP2zeffdd/5MpCxYsMLm5uWbZsmXmvffeM1dddZUpKSkxX375pf8aY8eONRdccIFZt26deeutt8xZZ51lrrvuunS9pXY70b6oq6szEydONIWFhWbz5s1J/3bEYjFjjDFvv/22eeSRR8zmzZvNjh07zO9+9zuTl5dnpkyZkuZ31jYn2g+HDh0y//qv/2rWrFljqqurzauvvmouvPBCc9ZZZ5mjR4/6r+HCMdGktrbWZGdnm0WLFrX4/Y46JpwLKMYY8+ijj5ri4mKTlZVlLr74YrN27dp0Tylwko57W7x4sTHGmJ07d5rLLrvM9OjRw4TDYXPmmWeaO++809TW1qZ34h1s0qRJJj8/32RlZZm/+Zu/MZMmTTLbt2/3n//yyy/NP//zP5szzjjDZGdnm3/4h38wNTU1aZxxsF555RUjyWzbti3p8dP9eHjjjTeO+/ehrKzMGHPso8Z33XWX6dOnjwmHw2bUqFEt9tHnn39urrvuOtOtWzeTk5Njpk2bZg4dOpSGd3NqTrQvqqurv/HfjjfeeMMYY8zGjRtNaWmpiUQipnPnzua73/2uuf/++5NO3N8GJ9oPR44cMVdccYXJy8szmZmZpl+/fmbGjBkt/sfWhWOiyeOPP266dOliDh482OL3O+qY8IwxpvX1FgAAgOA51YMCAAC+HQgoAADAOgQUAABgHQIKAACwDgEFAABYh4ACAACsQ0ABAADWIaAAAADrEFAAAIB1CCgAAMA6BBQAAGAdAgoAALDO/wcPUSxl4yrD4QAAAABJRU5ErkJggg==", 648 | "text/plain": [ 649 | "Figure(PyObject
)" 650 | ] 651 | }, 652 | "metadata": {}, 653 | "output_type": "display_data" 654 | } 655 | ], 656 | "source": [ 657 | "fig = plt.figure()\n", 658 | "plot(Uhist[1, 1:NRUNS])\n", 659 | "plot(Uhist[2, 1:NRUNS])\n", 660 | "plot(Uhist[3, 1:NRUNS])\n", 661 | "plt.legend([\"ux\", \"uy\", \"uz\"])\n", 662 | "fig" 663 | ] 664 | }, 665 | { 666 | "cell_type": "code", 667 | "execution_count": 231, 668 | "metadata": {}, 669 | "outputs": [ 670 | { 671 | "data": { 672 | "image/png": "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ZFQ+3n//fUGJTatjx45Vvs8jR45Uvvavf/0LP/30EzZs2ICDBw8iPT0djz/+uMC0pnH69Okqx2DPnj0AgNGjR1e2sdXzobi4GF27dsWSJUuqff3999/Hp59+iqVLl+LkyZNwc3NDVFQUtFptZZvx48fj0qVL2LNnD7Zv345Dhw5h2rRp5voWmkxtx6KkpAS//vor3njjDfz666/YtGkTEhIS8Oijj97RdsGCBVXOlb///e/miN9k6jonAGDYsGFVvsfvv/++yuv2cE4AqHIMMjIysGzZMshkMowaNapKu0afExLV6b777pOmT59e+dxgMEhBQUFSTEyMwFTml52dLQGQDh48WLmtf//+0j//+U9xoczkzTfflLp27Vrta/n5+ZJCoZA2bNhQue3y5csSAOn48eNmSijGP//5T6lVq1aS0WiUJMl+zgcA0ubNmyufG41GSa1WSx988EHltvz8fEmpVErff/+9JEmS9Ntvv0kApNOnT1e22bVrlySTyaS0tDSzZW9q//9YVOfUqVMSAOnGjRuV21q0aCF9/PHHpg1nRtUdh2effVYaOXJkjfvY8zkxcuRIadCgQVW2NcU5wZ6aOuh0OsTFxSEyMrJym4ODAyIjI3H8+HGBycyvoKAAAODj41Nl+5o1a+Dn54dOnTphzpw5KCkpERHP5K5evYqgoCC0bNkS48ePR0pKCgAgLi4Oer2+yjnSvn17hIaG2vQ5otPpsHr1akyePLnK4rH2cj78r6SkJGRmZlY5B7y8vNCrV6/Kc+D48ePw9vbGvffeW9kmMjISDg4OOHnypNkzm1NBQQFkMhm8vb2rbH/vvffg6+uLiIgIfPDBBygvLxcT0IRiY2MREBCAdu3a4cUXX8Tt27crX7PXcyIrKws7duzAc889d8drjT0nbG5By6Z269YtGAwGqFSqKttVKhWuXLkiKJX5GY1GvPTSS+jbty86depUuf2pp55CixYtEBQUhPPnz2P27NlISEjApk2bBKZter169cKKFSvQrl07ZGRk4K233sKDDz6IixcvIjMzE05OTnf8wlapVMjMzBQT2Ay2bNmC/Px8TJw4sXKbvZwP/9+f/87V/Z7487XMzEwEBARUed3R0RE+Pj42fZ5otVrMnj0b48aNq7J44T/+8Q90794dPj4+OHbsGObMmYOMjAx89NFHAtM2rWHDhuHxxx9HeHg4rl27hn//+98YPnw4jh8/DrlcbrfnxHfffQcPD487LtE3xTnBoobqZfr06bh48WKVcSQAqlz77dy5MwIDAzF48GBcu3YNrVq1MndMkxk+fHjl/3fp0gW9evVCixYtsH79eri4uAhMJs63336L4cOHIygoqHKbvZwPVD96vR5PPvkkJEnCF198UeW1mTNnVv5/ly5d4OTkhOeffx4xMTE2s5TA2LFjK/+/c+fO6NKlC1q1aoXY2FgMHjxYYDKxli1bhvHjx8PZ2bnK9qY4J3j5qQ5+fn6Qy+V33MmSlZUFtVotKJV5zZgxA9u3b8eBAwcQHBxca9tevXoBABITE80RTRhvb2+0bdsWiYmJUKvV0Ol0yM/Pr9LGls+RGzduYO/evZgyZUqt7ezlfPjz37m23xNqtfqOmwvKy8uRm5trk+fJnwXNjRs3sGfPniq9NNXp1asXysvLkZycbJ6AArRs2RJ+fn6VPw/2dk4AwOHDh5GQkFDn7w7g7s4JFjV1cHJyQo8ePbBv377KbUajEfv27UPv3r0FJjM9SZIwY8YMbN68Gfv370d4eHid+8THxwMAAgMDTZxOrKKiIly7dg2BgYHo0aMHFApFlXMkISEBKSkpNnuOLF++HAEBARgxYkSt7ezlfAgPD4dara5yDmg0Gpw8ebLyHOjduzfy8/MRFxdX2Wb//v0wGo2VxZ+t+LOguXr1Kvbu3QtfX98694mPj4eDg8Mdl2Nsyc2bN3H79u3Knwd7Oif+9O2336JHjx7o2rVrnW3v6pxo1DBjO7Fu3TpJqVRKK1askH777Tdp2rRpkre3t5SZmSk6mkm9+OKLkpeXlxQbGytlZGRUPkpKSiRJkqTExERpwYIF0pkzZ6SkpCRp69atUsuWLaV+/foJTt70Zs2aJcXGxkpJSUnS0aNHpcjISMnPz0/Kzs6WJEmSXnjhBSk0NFTav3+/dObMGal3795S7969Bac2DYPBIIWGhkqzZ8+ust3Wz4fCwkLp7Nmz0tmzZyUA0kcffSSdPXu28o6e9957T/L29pa2bt0qnT9/Xho5cqQUHh4ulZaWVn6NYcOGSREREdLJkyelI0eOSG3atJHGjRsn6lu6a7UdC51OJz366KNScHCwFB8fX+V3R1lZmSRJknTs2DHp448/luLj46Vr165Jq1evlvz9/aUJEyYI/s4aprbjUFhYKL388svS8ePHpaSkJGnv3r1S9+7dpTZt2kharbbya9jDOfGngoICydXVVfriiy/u2L+pzgkWNfX02WefSaGhoZKTk5N03333SSdOnBAdyeQAVPtYvny5JEmSlJKSIvXr10/y8fGRlEql1Lp1a+mVV16RCgoKxAY3gTFjxkiBgYGSk5OT1Lx5c2nMmDFSYmJi5eulpaXS3/72N6lZs2aSq6ur9Nhjj0kZGRkCE5vOzz//LAGQEhISqmy39fPhwIED1f48PPvss5IkVdzW/cYbb0gqlUpSKpXS4MGD7zhGt2/flsaNGye5u7tLnp6e0qRJk6TCwkIB303j1HYskpKSavzdceDAAUmSJCkuLk7q1auX5OXlJTk7O0sdOnSQ3n333Sof9tagtuNQUlIiDR06VPL395cUCoXUokULaerUqXf8MWwP58SfvvzyS8nFxUXKz8+/Y/+mOidkkiRJ9e/XISIiIrJMHFNDRERENoFFDREREdkEFjVERERkE1jUEBERkU1gUUNEREQ2gUUNERER2QQWNURERGQTWNQQERGRTWBRQ0RERDaBRQ0RERHZBBY1REREZBNY1BAREZFN+D+g89HF17xEYwAAAABJRU5ErkJggg==", 673 | "text/plain": [ 674 | "Figure(PyObject
)" 675 | ] 676 | }, 677 | "metadata": {}, 678 | "output_type": "display_data" 679 | } 680 | ], 681 | "source": [ 682 | "fig = plt.figure()\n", 683 | "plot(Xref[1,1:NRUNS], \"--\")\n", 684 | "plot(Xhist[1,1:NRUNS])\n", 685 | "plot(Xref[2,1:NRUNS], \"--\") \n", 686 | "plot(Xhist[2,1:NRUNS])\n", 687 | "plot(Xref[3,1:NRUNS], \"--\") \n", 688 | "plot(Xhist[3,1:NRUNS])\n", 689 | "plt.legend([\"xref\", \"x\", \"yref\", \"y\", \"zref\", \"z\"])\n", 690 | "# put limit on axis\n", 691 | "# plt.ylim(-5, 20)\n", 692 | "# plt.xlim(0, 300)\n", 693 | "fig" 694 | ] 695 | }, 696 | { 697 | "attachments": {}, 698 | "cell_type": "markdown", 699 | "metadata": {}, 700 | "source": [ 701 | "Post testing the procedure with the generated code, the next step involves deploying it for your specific applications/systems.\n", 702 | "The workflow for deployment is tailored to your specific needs, and we aim to provide clear guidance.\n", 703 | "\n", 704 | "Your `tiny_main` may look like this" 705 | ] 706 | }, 707 | { 708 | "attachments": {}, 709 | "cell_type": "markdown", 710 | "metadata": {}, 711 | "source": [ 712 | "```C\n", 713 | "#include \n", 714 | "\n", 715 | "#include \n", 716 | "#include \n", 717 | "\n", 718 | "using namespace Eigen;\n", 719 | "IOFormat CleanFmt(4, 0, \", \", \"\\n\", \"[\", \"]\");\n", 720 | "\n", 721 | "#ifdef __cplusplus\n", 722 | "extern \"C\" {\n", 723 | "#endif\n", 724 | "\n", 725 | "#define NTOTAL 201\n", 726 | "#define NRUNS (NTOTAL - NHORIZON - 1)\n", 727 | "#define dt 0.05\n", 728 | "\n", 729 | "float kp = 7.0;\n", 730 | "float kd = 3.0;\n", 731 | "float ki = 0.1;\n", 732 | "\n", 733 | "Vector3f integral;\n", 734 | "tiny_VectorNx xk;\n", 735 | "tiny_VectorNx xhrz;\n", 736 | "tiny_VectorNx xd;\n", 737 | "tiny_VectorNu uk;\n", 738 | "\n", 739 | "int main()\n", 740 | "{\n", 741 | "\tint NPOS = int(NSTATES/2);\n", 742 | "\tint exitflag = 1;\n", 743 | "\t// Double check some data\n", 744 | "\t// std::cout << tiny_data_solver.settings->max_iter << std::endl;\n", 745 | "\t// std::cout << tiny_data_solver.cache->AmBKt.format(CleanFmt) << std::endl;\n", 746 | "\t// std::cout << tiny_data_solver.work->Adyn.format(CleanFmt) << std::endl;\n", 747 | "\ttiny_data_solver.settings->en_state_bound = 1;\n", 748 | "\ttiny_data_solver.settings->max_iter = 100;\n", 749 | "\n", 750 | "\tfor (int i = 0; i < NHORIZON-1; i++)\n", 751 | "\t{\n", 752 | "\t\ttiny_data_solver.work->x_min.col(i) = -1.0 * tiny_VectorNx::Ones();\n", 753 | "\t\ttiny_data_solver.work->x_max.col(i) = 1.0 * tiny_VectorNx::Ones();\n", 754 | "\t\t// tiny_data_solver.work->u_min.col(i) << -3, -3, -1;\n", 755 | "\t\t// tiny_data_solver.work->u_max.col(i) << 1, 1, 1;\n", 756 | "\t}\n", 757 | "\n", 758 | "\tsrand(1);\n", 759 | "\txk = tiny_VectorNx::Random()*0.1;\n", 760 | "\n", 761 | "\tfor (int i = 0; i < NRUNS; i++)\n", 762 | "\t{\n", 763 | "\t\txhrz << xk;\n", 764 | "\t\t// Rollout the nominal system\n", 765 | "\t\tfor (int k = 0; k < NHORIZON-1; k++) {\n", 766 | "\t\t\tfloat temp = 2.0*sin(1*dt*i);\n", 767 | "\t\t\txd(seq(0,NPOS-1)) = temp * VectorXf::Ones(NPOS);\n", 768 | "\t\t\t// pid controller\n", 769 | "\t\t\tintegral = integral + (xd(seq(0,NPOS-1)) - xhrz(seq(0,NPOS-1)))*dt;\n", 770 | "\t\t\ttiny_data_solver.work->Uref.col(k) << kp*(xd(seq(0,NPOS-1)) - xhrz(seq(0,NPOS-1))) + kd*(xd(seq(NPOS,NSTATES-1)) - xhrz(seq(NPOS,NSTATES-1))) + 0*integral;\n", 771 | "\t\t\txhrz = tiny_data_solver.work->Adyn * xhrz + tiny_data_solver.work->Bdyn * tiny_data_solver.work->Uref.col(k);\n", 772 | "\t\t}\n", 773 | "\t\tuk = tiny_data_solver.work->Uref.col(0);\n", 774 | "\t\t\n", 775 | "\t\tif (1) { // enable safety filter\n", 776 | "\t\ttiny_data_solver.work->x.col(0) << xk;\n", 777 | "\n", 778 | "\t\texitflag = tiny_solve(&tiny_data_solver);\n", 779 | "\n", 780 | "\t\tuk = tiny_data_solver.work->u.col(0);\n", 781 | "\n", 782 | "\t\tif (exitflag != 1) printf(\"OOPS! Something went wrong!\\n\");\n", 783 | "\n", 784 | "\t\t// std::cout << tiny_data_solver.work->u.format(CleanFmt) << std::endl;\n", 785 | "\t\t}\n", 786 | "\t\txk = tiny_data_solver.work->Adyn * xk + tiny_data_solver.work->Bdyn * uk;\n", 787 | "\t\tstd::cout << \"xk = \" << xk.transpose() << std::endl;\n", 788 | "\t\tstd::cout << \"uk = \" << uk.transpose() << \"\\n\" << std::endl;\n", 789 | "\t}\n", 790 | "\treturn 0;\n", 791 | "}\n", 792 | "\n", 793 | "#ifdef __cplusplus\n", 794 | "} /* extern \"C\" */\n", 795 | "#endif\n", 796 | "\n", 797 | "```" 798 | ] 799 | }, 800 | { 801 | "attachments": {}, 802 | "cell_type": "markdown", 803 | "metadata": {}, 804 | "source": [] 805 | } 806 | ], 807 | "metadata": { 808 | "kernelspec": { 809 | "display_name": "Julia 1.6.7", 810 | "language": "julia", 811 | "name": "julia-1.6" 812 | }, 813 | "language_info": { 814 | "file_extension": ".jl", 815 | "mimetype": "application/julia", 816 | "name": "julia", 817 | "version": "1.6.7" 818 | }, 819 | "orig_nbformat": 4 820 | }, 821 | "nbformat": 4, 822 | "nbformat_minor": 2 823 | } 824 | -------------------------------------------------------------------------------- /examples/visualization.jl: -------------------------------------------------------------------------------- 1 | # courtesy of Kevin Tracy 2 | import MeshCat as mc 3 | using ColorTypes 4 | using GeometryBasics: HyperRectangle, Cylinder, Vec, Point, Mesh 5 | using CoordinateTransformations 6 | using Rotations 7 | 8 | function rotx(θ) 9 | s, c = sincos(θ) 10 | return [1 0 0; 0 c -s; 0 s c] 11 | end 12 | function create_cartpole!(vis) 13 | mc.setobject!(vis[:cart], mc.HyperRectangle(mc.Vec(-.25,-1.0,-.15), mc.Vec(0.5,2,0.3))) 14 | mc.setobject!(vis[:pole], mc.Cylinder(mc.Point(0,0,-.75), mc.Point(0,0,.75), 0.05)) 15 | mc.setobject!(vis[:a], mc.HyperSphere(mc.Point(0,0,0.0),0.1)) 16 | mc.setobject!(vis[:b], mc.HyperSphere(mc.Point(0,0,0.0),0.1)) 17 | end 18 | function update_cartpole_transform!(vis,x) 19 | pole_o = 0.3 20 | px = x[1] 21 | θ = x[3] 22 | mc.settransform!(vis[:cart], mc.Translation([0,px,0.0])) 23 | p1 = [pole_o,px,0] 24 | p2 = p1 + 1.5*[0, sin(θ), -cos(θ)] 25 | mc.settransform!(vis[:a], mc.Translation(p1)) 26 | mc.settransform!(vis[:b], mc.Translation(p2)) 27 | mc.settransform!(vis[:pole], mc.Translation(0.5*(p1 + p2)) ∘ mc.LinearMap(rotx(θ))) 28 | end 29 | 30 | function animate_cartpole(X, dt) 31 | print(length(X)) 32 | vis = mc.Visualizer() 33 | create_cartpole!(vis) 34 | anim = mc.Animation(floor(Int,1/dt)) 35 | for k = 1:length(X) 36 | mc.atframe(anim, k) do 37 | update_cartpole_transform!(vis,X[k]) 38 | end 39 | end 40 | mc.setanimation!(vis, anim) 41 | return mc.render(vis) 42 | end 43 | 44 | function mat_from_vec(X) 45 | # convert a vector of vectors to a matrix 46 | Xm = hcat(X...) 47 | return Xm 48 | end 49 | 50 | function visualize_quad_state(X) 51 | # visualize the state history of the quadrotor 52 | X_m = mat_from_vec(X) 53 | display(plot(X_m[1:7,:]',label=["x" "y" "z" "qw" "qx" "qy" "qz"], 54 | linestyle=[:solid :solid :solid :dash :dash :dash :dash], linewidth=[2 2 2 2 2 2 2], 55 | title="State History", xlabel="time (s)", ylabel="x")) 56 | end 57 | 58 | function visualize_quad_xy(Xreal, Xref=nothing) 59 | # visualize the xy position of the quadrotor 60 | if Xref != nothing 61 | X_m = mat_from_vec(Xref) 62 | plot(X_m[2,:],X_m[1,:],label="ref", 63 | linestyle=:solid, linewidth=2, 64 | title="State History", xlabel="y", ylabel="x") 65 | X_m = mat_from_vec(Xreal) 66 | display(plot!(X_m[2,:],X_m[1,:],label="real", linestyle=:dash, linewidth=2, 67 | title="State History", xlabel="y", ylabel="x", aspect_ratio=:equal)) 68 | else 69 | X_m = mat_from_vec(Xreal) 70 | display(plot(X_m[2,:],X_m[1,:],label="real", linestyle=:dash, linewidth=2, 71 | title="State History", xlabel="y", ylabel="x", aspect_ratio=:equal)) 72 | end 73 | end -------------------------------------------------------------------------------- /tinympc/Project.toml: -------------------------------------------------------------------------------- 1 | name = "TinyMPC" 2 | uuid = "30135025-f3e0-4050-9784-f9d33a970231" 3 | authors = ["xkhainguyen "] 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /tinympc/TinyMPC.jl: -------------------------------------------------------------------------------- 1 | module TinyMPC 2 | 3 | # Temporary package 4 | # There can be better ways to do this 5 | 6 | # Compile the generated code 7 | function compile_lib(dir::String) 8 | print("Compiling library to ", dir, "\n") 9 | build_dir = joinpath(dir, "build") 10 | if !isdir(build_dir) 11 | mkdir(build_dir) 12 | end 13 | run(`cmake -S $dir -B $build_dir`) 14 | run(`cmake --build $build_dir`) 15 | return true 16 | end 17 | 18 | end # module 19 | --------------------------------------------------------------------------------