title | permalink | layout | description |
---|---|---|---|
Getting Started |
examples |
page |
Some simple examples of how to use MPPI-Generic |
{% include math_functions.md %} {% assign use_output = false %}
This library is made up of 6 major types of classes:
- Dynamics
- Cost Functions
- Controllers
- Sampling Distributions
- Feedback Controllers
- Plants
The Dynamics and Cost Function classes are self-evident and are classes describing the
For those who want to use pre-existing Dynamics and Cost Functions, the MPPI-Generic library provides a large variety. Pre-existing Dynamics include a quadcopter, 2D double integrator, cartpole, differential-drive robot [2], various Autorally models [3], and various models learned for a Polaris RZR X [4]. The various Cost Functions included are mostly specific to each Dynamics model but we do provide a Dynamics-agnostic quadratic cost as well.
There are two ways to use the MPPI-Generic library: stand-alone or as a MPC controller.
{% capture min_example %}{% include_relative submodules/MPPI_Paper_Example_Code/src/minimal_example.cu %}{% endcapture %} {% highlight cpp linenos %} {{ min_example }} {% endhighlight %} Listing 1: Minimal example used in a stand-alone fashion {: class="codecaption"}
{% assign min_lines = min_example | newline_to_br | split: '
' %}
If you just wanted to run a single iteration of MPPI in order to get an optimal control sequence, the code in Lst 1 provides a minimal working example.
{% highlight cpp %}
{% for line in min_lines offset:0 limit:5 %}{{ line }}{% endfor %}
{% endhighlight %}
Breaking it down, we start by including the controller, dynamics, cost function, and feedback controller headers used in this example.
Again, by default, the feedback controller will not be used but it is required for the MPPI controller.
In this example, we are using a cartpole system with a quadratic cost function to swing up the pole of the cart.
The controller we will be using is the standard MPPI controller.
{% highlight cpp %}
{% for line in min_lines offset:5 limit:3 %}{{ line }}{% endfor %}
{% endhighlight %}
Next, we define the number of timesteps
{% highlight cpp %}
{% for line in min_lines offset:16 limit:10 %}{{ line }}{% endfor %}
{% endhighlight %}
Then in the main method, we first set up the controller_params
, and ensure we set the computeControl()
.
The optimal control sequence is then returned as an Eigen::Matrix
from getControLSequence()
and printed out to the terminal.
{% highlight cpp linenos %} {% include_relative submodules/MPPI_Paper_Example_Code/include/mppi_paper_example/plants/cartpole_plant.hpp %} {% endhighlight %} Listing 2: Basic Plant implementation that interacts with a virtual Cartpole Dynamics system stored internal to the Plant. {: class="codecaption"}
When using MPPI in a MPC fashion, we need to use a Plant wrapper around our controller.
The Plant houses methods to obtain new data such as state, calculate the optimal control sequence at a given rate using the latest information available, and provide the latest control to the external system
while providing the necessary tooling to ensure there are no race conditions.
As this is the class that provides the interaction between the algorithm and the actual system, it is a component that has to be modified for every use case.
For this example, we will implement a plant inheriting from BasePlant
that houses the external system completely internal to the class.
Specifically, we will write our plant to run the dynamics inside pubControl()
in order to produce a new state.
We shall then call updateState()
at a different fixed rate from the controller re-planning rate to show that the capability of the code base.
In Lst. 2, we can see a simple implementation of a Plant.
SimpleCartpolePlant
instantiates a CartpoleDynamics
variable upon creation, overwrites the required virtual methods from BasePlant
, and sets up the dynamics update to occur within pubControl()
.
Looking at the constructor, we pass a shared pointer to a Controller, an integer representing the controller replanning rate, and the minimum timestep we want to adjust the control trajectory by when performing multiple optimal control calculations to the base Plant constructor, and then create our stand-in system dynamics.
pubControl()
is where we send the control to the system and so in this case, we create necessary extra variables and then pass the current state prev_state
and u
respectively to the Dynamics' step()
method to get the next state, current_state_
.
We also update the current time to show that system has moved forward in time.
Looking at this class, a potential issue arises as it is templated on the controller which in turn might not use CartpoleDynamics
as its Dynamics class.
This can be easily remedied by replacing any reference to CarpoleDynamics
with CONTROLLER_T::TEMPLATED_DYNAMICS
to make this plant work with the Dynamics used by the instantiated Controller.
Now that we have written our specialized Plant class, we can then go back to the minimal example and make some modifications to use the controller in a MPC fashion, shown in Lst. 3.
For this example, we will just run a simple for
loop that calls the Plant's runControlIteration()
and updateState()
methods to simulate a receiving a new state from the system and then calculating a new optimal control sequence from it.
The updateState()
method calls pubControl()
internally so the system state and the current time will get updated as this runs.
For real-time scenarios, there is also the runControlLoop()
Plant method which can be launched in a separate thread and calls runControlIteration()
internally at the specified replanning rate.
{% highlight cpp linenos %} {% include_relative submodules/MPPI_Paper_Example_Code/src/minimal_mpc_example.cu %} {% endhighlight %} Listing 3: Minimal example used in a MPC fashion {: class="codecaption"}
[1] S. Macenski, T. Foote, B. Gerkey, C. Lalancette, and W. Woodall, "Robot Operating System 2: Design, architecture, and uses in the wild," Science Robotics, vol. 7, no. 66, p. eabm6074, May 2022. [Online]. Available: https://www.science.org/doi/10.1126/scirobotics.abm6074
[2] J.-P. Laumond et al., Robot Motion Planning and Control. Springer, 1998, vol. 229.
[3] G. Williams, P. Drews, B. Goldfain, J. M. Rehg, and E. A. Theodorou, "Information-Theoretic Model Predictive Control: Theory and Applications to Autonomous Driving," IEEE Transactions on Robotics, vol. 34, no. 6, pp. 1603-1622, 2018. [Online]. Available: https://ieeexplore.ieee.org/document/8558663
[4] J. Gibson, B. Vlahov, D. Fan, P. Spieler, D. Pastor, A.-a. Agha-mohammadi, and E. A. Theodorou, "A Multi-step Dynamics Modeling Framework For Autonomous Driving In Multiple Environments," in 2023 IEEE International Conference on Robotics and Automation (ICRA). IEEE, May 2023, pp. 7959-7965. [Online]. Available: https://ieeexplore.ieee.org/document/10161330