Contents¶
Introduction¶
To make use of CRS we must first ensure that we have an appropriate model. Currently, CRS includes pacejka and kinematic models for the miniature racing system, and models for parafoil and rocket systems were recently added.
If none of these systems suit your use case then it may be necessary to define a new model. Luckily CRS provides a template so users can easily add a new model and take advantage of CRS' built in functionality! The custom model template can be found in src/crs/dynamic_models/custom_model_template.
By duplicating this entire directory all we will have to do is redefine our paramters, state, and inputs, update the dynamics and rename files accordingly. In this example we use the parafoil_4dof model as a placeholder.
Tip: It makes sense to use a descriptive prefix (e.g: parafoil_4dof_) together with systematic use of the find-and-replace function in your IDE to rename the custom_ model's variables.
| prefix | model | state |
|---|---|---|
custom_(model) |
custom_model_continuous |
custom_state |
parafoil_4dof_ |
parafoil_4dof_continuous |
parafoil_4dof_state |
Step-by-Step¶
Duplicate Template Folder¶
Duplicate custom_model_template & rename e.g to parafoil_4dof_model
custom_model_template
├── CMakeLists.txt
├── config
│ └── model_params.yaml
├── include
│ └── custom_model_template
│ ├── custom_input.h
│ ├── custom_model_continuous.h
│ ├── custom_model_discrete.h
│ ├── custom_params.h
│ └── custom_state.h
├── package.xml
└── src
├── custom_model_continuous.cpp
├── custom_model_discrete.cpp
└── utils
└── data_conversion.cpp
Configuration Files¶
Update config/model_params/
- rename
type - resize
Q - update model parameters
Header Files¶
Update include/custom_model_template/
- rename folder
- Update
custom_params.h- rename file
- update ifdefs, e.g. to
PARAFOIL_4DOF_MODEL_PARAFOIL_4dof_PARAMS - replace all
custom_*, this will automatically- rename namespace
- rename struct
- update params to match config
- rename/update struct components
- update operators
- Update
custom_state.h- rename file
- update ifdefs
- find & replace all
custom_* - rename/update struct components
- update operators
- Update
custom_input.h- rename file
- update ifdefs
- find & replace all
custom_* - rename/update struct components
- update operators
- Update
custom_model_continuous.h- rename file
- update ifdefs
- update includes
- rename
ContinuousCustomModelas desired - find & replace all
custom_* - update state/input matrix dimensions
- Update
custom_model_discrete.h- rename file
- update ifdefs
- update includes
- rename
DiscreteCustomModel - find & replace all
custom_* - update state/input dimensions
Source Files¶
Update src/
- Update
custom_model_continuous.cpp- rename file
- update includes
- find & replace all
custom_* - rename
ContinuousCustomModelas desired - rename states/inputs in constructor
-
Update dynamics in
getContinuousDynamicsto match your desired model. Shown below are the dynamics for the 4 degrees-of-freedom parafoil model/** * @brief Get the analytical state equations f(state, input) = state_dot * * @param state * @param control_input * @return std::vector<casadi::MX> returns the analytical state equations f(state, input) = state_dot */ std::vector<casadi::MX> ContinuousParafoil4dofModel::getContinuousDynamics(const std::vector<casadi::MX> state, const std::vector<casadi::MX> control_input) { using namespace casadi; // Just for better readability, function inputs (states and control inputs) auto x = state[0]; // Make sure to match these with states MX defined in constructor // --snip-- auto w = state[8]; auto deflection_symmetric = control_input[0]; auto deflection_asymmetric = control_input[1]; // Intermediate function values auto V_a = sqrt(pow(u,2) + pow(w,2)); auto alpha = atan2(w,u); auto q = params.rho*pow(V_a, 2)/2; auto L = q*params.S*(params.C_L0 + params.C_Ldelta_s * deflection_symmetric); auto D = q*params.S*(params.C_D0 + params.C_Ddelta_s * deflection_symmetric); Eigen::Matrix<casadi::MX, 3, 3> R_bn; R_bn(0, 0) = cos(psi)*cos(theta); // --snip-- R_bn(2, 2) = cos(theta)*cos(phi); Eigen::Matrix<casadi::MX, 3, 1> body_rate(u, v, w); Eigen::Matrix<casadi::MX, 3, 1> ned_rate = R_bn.transpose() * body_rate; auto phi_rate = (-phi + params.K_phi * deflection_asymmetric)/params.T_phi; auto psi_rate = 9.81*tan(phi)/u + w*phi_rate/(u*cos(phi)); // Output of f(state, control) auto x_dot = ned_rate(0); auto y_dot = ned_rate(1); auto z_dot = ned_rate(2); auto phi_dot = phi_rate; auto theta_dot = 0.0; auto psi_dot = psi_rate; auto u_dot = (L*sin(alpha) - D*cos(alpha))/params.m - w*psi_rate*sin(phi); auto v_dot = 0.0; auto w_dot = (-L*cos(alpha) - D*sin(alpha))/params.m + 9.81*cos(phi) + u*psi_rate*sin(phi); std::vector<casadi::MX> state_dot = { x_dot, y_dot, z_dot, phi_dot, theta_dot, psi_dot, u_dot, v_dot, w_dot }; return state_dot; } -
Update
custom_model_discrete.cpp- rename file
- update includes
- find & replace all
custom_* - rename
ContinuousCustomModel&DiscreteCustomModelmatching header files - rename states/inputs in constructor (matching continuous case)
- resize state/input dimensions
- Update
utils/data_conversion- update includes
- find & replace all
custom_* - also replace
custom_model_template - update state/input vectors
- resize state dimensions
Admin Files¶
Update CMakeLists.txt
- rename project
- rename libraries
Update package.xml
- rename package
name - write package description
- update author email & name
Review¶
Folder structure should then be equivalent to the following:
parafoil_4dof_model
├── CMakeLists.txt
├── config
│ └── model_params.yaml
├── include
│ └── parafoil_4dof_model
│ ├── parafoil_4dof_input.h
│ ├── parafoil_4dof_continuous.h
│ ├── parafoil_4dof_discrete.h
│ ├── parafoil_4dof_params.h
│ └── parafoil_4dof_state.h
├── package.xml
└── src
├── parafoil_4dof_continuous.cpp
├── parafoil_4dof_discrete.cpp
└── utils
└── data_conversion.cpp
Up Next¶
Now that we have defined our system dynamics model we can define our sensor models in the next tutorial. With both of these models defined in CRS we will be able to call these classes/their methods from ROS to easily simulate our system, but let's not get ahead of ourselves