diff --git a/.gitignore b/.gitignore index 61482a8..aa87008 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /Manifest.toml -/.CondaPkg \ No newline at end of file +/.CondaPkg +/gen/Manifest.toml +/examples/Manifest.toml \ No newline at end of file diff --git a/Project.toml b/Project.toml index 3f13d52..2bddbd7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,12 +1,10 @@ name = "QuanserInterface" uuid = "d7748c0a-89fb-413b-a9f0-29aba34b281f" authors = ["Fredrik Bagge Carlson"] -version = "1.0.0-DEV" +version = "0.1.0-DEV" [deps] -CBinding = "d43a6710-96b8-4a2d-833c-c424785e5374" CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" -Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31" ControlSystemIdentification = "3abffc1c-5106-53b7-b354-a47bfc086282" ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e" DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2" @@ -14,23 +12,18 @@ DiscretePIDs = "c1363496-6848-4723-8758-079b737f6baf" HardwareAbstractions = "9ac91abb-62f4-42c0-88e8-83732e93d543" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LowLevelParticleFilters = "d9d29d28-c116-5dba-9239-57a5fe23875b" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Preferences = "21216c6a-2e73-6563-6e65-726566657250" RobustAndOptimalControl = "21fd56a4-db03-40ee-82ee-a87907bee541" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - [weakdeps] PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" [extensions] QuanserInterfacePythonCallExt = ["PythonCall"] - [compat] -CBinding = "1.0.10" -CEnum = "0.4.2" -Clang = "0.17.6" +CEnum = "0.4.2, 0.5" ControlSystemIdentification = "2.6" ControlSystemsBase = "1.7.0" DSP = "0.7.8" @@ -44,8 +37,8 @@ StaticArrays = "1.5" julia = "1.9" [extras] -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["Test"] diff --git a/README.md b/README.md index 42a9ad3..c564606 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,19 @@ See the Youtube vidoe series [Control of a rotary pendulum using Julia](https:// ## Installation 1. Install the hardware-in-the-loop (HIL) interface from here https://github.com/quanser/hil_sdk_linux_x86_64 (change linux to what's appropriate for your system) -2. To use the `PythonBackend` Install Quanser python packages as described [here](https://docs.quanser.com/quarc/documentation/python/installation.html) and manually install and load PythonCall (the python backend is an extension). Optionally, set the default backend using `QuanserInterface.set_default_backend("python")`. Install the Virtual Environment first, which will include the Python Wheels. -3. To use the C backend (default), install the sdk, and if on Linux, possibly symlink `sudo ln -s /usr/lib/x86_64-linux-gnu/libquanser_communications.so.1 /lib/libquanser_communications.so` (or wherever the library is located on your system), I had issues with the `.1` suffix causing Libdl not to find the library. The easiest way to install all the required shared libraries is to follow the python install instructions, i.e., issue the `sudo apt install python3-quanser-apis` after having added their package server. +2. To use the `CBackend` (default), install the Quanser HIL SDK ([mac], [linux], [windows]) + +
+ + Linux tips + +If on Linux, possibly symlink `sudo ln -s /usr/lib/x86_64-linux-gnu/libquanser_communications.so.1 /lib/libquanser_communications.so` (or wherever the library is located on your system), I had issues with the `.1` suffix causing Libdl not to find the library. The easiest way to install all the required shared libraries _on linux_ is to follow the python install instructions, i.e., issue the `sudo apt install python3-quanser-apis` after having added their package server. + +
+ +--- + +3. To use the `PythonBackend`, install Quanser python packages as described [here](https://docs.quanser.com/quarc/documentation/python/installation.html), and manually install and load `PythonCall.jl` (the python backend is an extension). Optionally, set the default backend using `QuanserInterface.set_default_backend("python")`. Install the Virtual Environment first, which will include the Python Wheels. ### Virtual environment diff --git a/examples/Project.toml b/examples/Project.toml new file mode 100644 index 0000000..32bd5fd --- /dev/null +++ b/examples/Project.toml @@ -0,0 +1,15 @@ +[deps] +ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" +HardwareAbstractions = "9ac91abb-62f4-42c0-88e8-83732e93d543" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +LowLevelParticleFilters = "d9d29d28-c116-5dba-9239-57a5fe23875b" +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +QuanserInterface = "d7748c0a-89fb-413b-a9f0-29aba34b281f" + +[sources] +QuanserInterface = { path = ".." } \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index e0a3ed1..ca559e5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,2 +1,10 @@ # Examples -Each example has a little description at the top. \ No newline at end of file +Each example has a little description at the top. + +To run an example, you can do this. + +```bash +QuanserInterface.jl/> julia --project=. examples/swingup.jl +``` + +and it will just run. The examples must be run in the `QuanserInterface.jl` project. \ No newline at end of file diff --git a/examples/pendulum_identification.jl b/examples/pendulum_identification.jl index 80b5d64..c1959d8 100644 --- a/examples/pendulum_identification.jl +++ b/examples/pendulum_identification.jl @@ -3,7 +3,7 @@ This script performs maximum likelihood estimation of the parameters of the pend The estimation uses an UnscentedKalmanFilter to perform state estimation, the system is unstable and integrates a force disturbance, and performing identification using a state estimator is a good way of handling both those problems. =# -cd(@__DIR__) + using DelimitedFiles, Plots N = 250 D = readdlm("swingup.csv", ',')[2:N, :] .|> identity diff --git a/examples/swingup.jl b/examples/swingup.jl index 8f4772e..cf1da97 100644 --- a/examples/swingup.jl +++ b/examples/swingup.jl @@ -1,8 +1,12 @@ #= This script performs swingup of the pendulum using an energy-based controller, and stabilizes the pendulum at the top using an LQR controller. The controller gain is designed using furuta_lqg.jl =# -cd(@__DIR__) -using Pkg; Pkg.activate("..") + +if splitdir(Base.active_project())[1] != @__DIR__ + @warn "Not in the QuanserInterface.jl/examples project, activating it" + using Pkg; Pkg.activate(@__DIR__) +end + using QuanserInterface using HardwareAbstractions using ControlSystemsBase diff --git a/examples/virtual_swingup.jl b/examples/virtual_swingup.jl index 8f54a54..f26f363 100644 --- a/examples/virtual_swingup.jl +++ b/examples/virtual_swingup.jl @@ -1,8 +1,12 @@ #= This script performs swingup of the virtual pendulum using an energy-based controller, and stabilizes the pendulum at the top using an LQR controller. =# -cd(@__DIR__) -using Pkg; Pkg.activate("..") + +if splitdir(Base.active_project())[1] != @__DIR__ + @warn "Not in the `QuanserInterface.jl/examples` project, activating it" + using Pkg; Pkg.activate(@__DIR__) +end + using QuanserInterface using HardwareAbstractions using ControlSystemsBase diff --git a/src/Generator.toml b/gen/Generator.toml similarity index 100% rename from src/Generator.toml rename to gen/Generator.toml diff --git a/gen/Project.toml b/gen/Project.toml new file mode 100644 index 0000000..f36be7f --- /dev/null +++ b/gen/Project.toml @@ -0,0 +1,2 @@ +[deps] +Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31" diff --git a/src/QuanserCGenerator.jl b/gen/QuanserCGenerator.jl similarity index 80% rename from src/QuanserCGenerator.jl rename to gen/QuanserCGenerator.jl index 9bc8cbd..d3a9e65 100644 --- a/src/QuanserCGenerator.jl +++ b/gen/QuanserCGenerator.jl @@ -2,7 +2,7 @@ using Clang.Generators LIB_PATH = "/opt/quanser/hil_sdk/include" headers = [joinpath(LIB_PATH, header) for header in filter(x -> endswith(x, ".h"), readdir(LIB_PATH))] # include all .h files in the directory -output = "src/QuanserBindings.jl" +output = joinpath(@__DIR__, "QuanserBindings.jl") # make sure Clang.jl can find necessary headers included by your header file clang_args = ["-I", LIB_PATH] @@ -20,4 +20,4 @@ ctx = create_context(headers, args, options) # run generator build!(ctx) -println("Bindings generated in $output") +println("Bindings generated in $output.\nPlease copy the file to src/QuanserBindings.jl")