cart-pole-mpc is a toy implementation of Model Predictive Control (MPC) for a cart-pole system. The controller itself is written in C++, but compiles for the web using emscripten and WebAssembly (WASM). I wrote this to learn more about MPC, and also to experiment with deploying WASM apps to the web. See the blog post for more context.
This section outlines the steps required to build the web-app. You will need the following prerequisites:
- CMake >= 3.20
- emscripten: setup instructions
- Node
git clone https://github.com/gareth-cross/cart-pole-mpc
cd cart-pole-mpc
git submodule update --init --recursivesource <PATH WHERE YOU CLONED EMSDK>/emsdk_env.shMake sure that the build of Node that ships with emscripten has TypeScript installed. emscripten installs node to $EMSDK_NODE. Find the adjacent npm executable and run npm install typescript.
mkdir build
cd build
emcmake cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_WITH_EMSCRIPTEN=ONIf you want debug symbols embedded in the WASM, change the build type to RelWithDebInfo. C++ function names should then be visible in WASM stacktraces.
emmake make -j8NOTE: CCFLAGS or LDFLAGS when running the project configuration, these invalid flags may get passed to em++. Some package managers like conda will touch these environment variables. I suggest explicitly clearing them before configuration.
This step should place two files in viz/src: optimization-wasm.js and optimization-wasm.d.ts.
cd viz
npm ci
npm run dev🎉 Ta-da! Now you can play with the app locally.
This project uses wrenfold to code-generate the system dynamics. First install wrenfold and SymPy via either pip or conda.
pip install wrenfold sympyTo change the dynamics, edit symbolic/dynamics_single.py and run the generation script:
python -m symbolic.generateThe optimization can also be run via a nanobind python wrapper. This is useful for offline debugging or generating plots in matplotlib/plotly.
The following command requires that Python>=3.9 is available on the path:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfoNote: If you want to build both the emscripten bindings and the python module, you should probably create two different build directories.
Then compile by running:
cmake --build .This should produce pypendulum.**.so in build/wrapper/.
This is not really intended to be a production piece of software, but PRs are welcome if you find something broken. This project uses pre-commit to enforce code-formatting.
The TypeScript/JavaScript components can be formatted by running npm run prettier-format in the viz/dist directory.
cart-pole-mpc is MIT Licensed.
