Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(learned_model): create package #6395

Merged
merged 104 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
ddd4efa
Add a new simulation model
atomyks Dec 6, 2023
ef04b57
Add new model -> currently same as delay_steer_vel
atomyks Dec 6, 2023
b2d18af
Add python.h library
atomyks Dec 8, 2023
0cf474d
Add working simple steering model programed in python launched from C++
atomyks Dec 8, 2023
ec66297
Fixing linker problem (WIP)
atomyks Dec 13, 2023
e183aac
Split python models to models and learned model
atomyks Dec 18, 2023
e4a65b4
Changes from Maxime
atomyks Dec 19, 2023
6bebdcd
Fix build issiues
atomyks Dec 19, 2023
30dfee2
Add C++ library that runs python models
atomyks Jan 18, 2024
814ae25
Update CMakeList
atomyks Jan 18, 2024
0f4715c
Add python model to simulation models
atomyks Jan 18, 2024
aec7d7c
Fix path to the python model parameters
atomyks Jan 18, 2024
903c9b5
Fix minor formatting
atomyks Jan 23, 2024
0d42c69
Add README (WIP)
atomyks Jan 23, 2024
c62c915
Minor bugfix
atomyks Jan 23, 2024
3c72983
Remove explicit error-model. All sub-models should be properly enclosed.
atomyks Jan 23, 2024
cd4b82b
Remove explicit error-model. All sub-models should be properly enclosed.
atomyks Jan 23, 2024
1fae8c6
Simplify pymodel interface
atomyks Jan 23, 2024
3f24a26
Fix formatting
atomyks Jan 23, 2024
88043aa
Fix formatting and add comments
atomyks Jan 24, 2024
19f7d40
Remove unnecessary model parameters
atomyks Jan 24, 2024
a6bdfc3
Remove unused functions
atomyks Jan 24, 2024
474dc37
Minor bugfixes
atomyks Jan 24, 2024
c3a9164
Add vy and yaw rate to model states
atomyks Jan 24, 2024
01bbf00
Add example to README and API doc (WIP)
atomyks Jan 24, 2024
dbe3aab
Fix bug in CMakeList
atomyks Jan 26, 2024
e41d955
Fix import bugs and fix formatting
atomyks Jan 26, 2024
39b9de4
Add model descriptor to ros2 parameter file
atomyks Jan 27, 2024
cc057e0
Change char* to std::string in model descriptor
atomyks Jan 27, 2024
7eba8c1
Minor code cleanup
atomyks Jan 27, 2024
dfeb12a
Minor code cleanup
atomyks Jan 29, 2024
602eadf
Add method to set time stamp from C++
atomyks Jan 29, 2024
ed65c60
Update README
atomyks Jan 29, 2024
362a536
Split implementation between .hpp and .cpp files
atomyks Jan 30, 2024
bf77450
Fix bug multiple definitions of functions
atomyks Jan 30, 2024
7a67372
Add missing definition
atomyks Jan 30, 2024
95a271b
Fix symbol visibility problem
atomyks Feb 5, 2024
dbc2d1f
Merge pull request #1 from atomyks/bug/file_split
atomyks Feb 5, 2024
47023de
Change naming to better represent functionality of classes and files
atomyks Feb 5, 2024
90be653
Improve documentation
atomyks Feb 5, 2024
9b6060a
Add learned model parameters to the simple_planning_simulator
atomyks Feb 5, 2024
f6d40da
Add a new simulation model
atomyks Dec 6, 2023
a326e1f
Add new model -> currently same as delay_steer_vel
atomyks Dec 6, 2023
cd229e2
Add python.h library
atomyks Dec 8, 2023
b577a45
Add working simple steering model programed in python launched from C++
atomyks Dec 8, 2023
389b941
Fixing linker problem (WIP)
atomyks Dec 13, 2023
c131e3b
Split python models to models and learned model
atomyks Dec 18, 2023
9e5c33c
Changes from Maxime
atomyks Dec 19, 2023
12f6122
Fix build issiues
atomyks Dec 19, 2023
373c72b
Add C++ library that runs python models
atomyks Jan 18, 2024
f6cedfe
Update CMakeList
atomyks Jan 18, 2024
e697eea
Add python model to simulation models
atomyks Jan 18, 2024
204f0da
Fix path to the python model parameters
atomyks Jan 18, 2024
1d26ec3
Fix minor formatting
atomyks Jan 23, 2024
7fbfe64
Add README (WIP)
atomyks Jan 23, 2024
2f68197
Minor bugfix
atomyks Jan 23, 2024
cfd0b8b
Remove explicit error-model. All sub-models should be properly enclosed.
atomyks Jan 23, 2024
5693dba
Remove explicit error-model. All sub-models should be properly enclosed.
atomyks Jan 23, 2024
fe66857
Simplify pymodel interface
atomyks Jan 23, 2024
42a2414
Fix formatting
atomyks Jan 23, 2024
97aacdf
Fix formatting and add comments
atomyks Jan 24, 2024
91ea6c1
Remove unnecessary model parameters
atomyks Jan 24, 2024
3797ce2
Remove unused functions
atomyks Jan 24, 2024
85353cb
Minor bugfixes
atomyks Jan 24, 2024
1c5d296
Add vy and yaw rate to model states
atomyks Jan 24, 2024
c9afcee
Add example to README and API doc (WIP)
atomyks Jan 24, 2024
6595477
Fix bug in CMakeList
atomyks Jan 26, 2024
7f9398d
Fix import bugs and fix formatting
atomyks Jan 26, 2024
014a2ad
Add model descriptor to ros2 parameter file
atomyks Jan 27, 2024
5a1b299
Change char* to std::string in model descriptor
atomyks Jan 27, 2024
14eaafb
Minor code cleanup
atomyks Jan 27, 2024
741743a
Minor code cleanup
atomyks Jan 29, 2024
be53055
Add method to set time stamp from C++
atomyks Jan 29, 2024
dd38d72
Update README
atomyks Jan 29, 2024
767f045
Split implementation between .hpp and .cpp files
atomyks Jan 30, 2024
89ed5e9
Fix bug multiple definitions of functions
atomyks Jan 30, 2024
5c018e2
Add missing definition
atomyks Jan 30, 2024
de4755c
Fix symbol visibility problem
atomyks Feb 5, 2024
f830675
Change naming to better represent functionality of classes and files
atomyks Feb 5, 2024
603f47d
Improve documentation
atomyks Feb 5, 2024
bdcb57f
Resolve conflicts
atomyks Feb 13, 2024
6c15e69
Merge branches
atomyks Feb 13, 2024
f35c93a
Merge branch 'autowarefoundation:main' into feature/simulator_py_model
atomyks Feb 13, 2024
9fd5303
Fix naming on parameter, change documentation accordingly
atomyks Feb 13, 2024
46ce53e
style(pre-commit): autofix
pre-commit-ci[bot] Feb 13, 2024
35523fc
Add copyright
atomyks Feb 19, 2024
9dd0557
Remove prints
atomyks Feb 19, 2024
95ebf2d
Fix maintainer email
atomyks Feb 19, 2024
11ed37b
Fix documentation
atomyks Feb 19, 2024
5792a50
Improve documentation
atomyks Feb 19, 2024
219f4b4
style(pre-commit): autofix
pre-commit-ci[bot] Feb 19, 2024
3d3b26d
Improve documentation
atomyks Mar 4, 2024
8dbca89
Merge branch 'main' into feature/simulator_py_model
atomyks Mar 5, 2024
2f4ca6d
Fix unnecessary comments
atomyks Mar 11, 2024
83d146c
Merge branch 'main' into feature/simulator_py_model
atomyks Mar 11, 2024
82803cc
Merge branch 'main' into feature/simulator_py_model
atomyks Mar 19, 2024
c31ae9f
Fix pre-commit check errors
atomyks Mar 19, 2024
47a1d0e
Fix pybind11 name in package.xml
atomyks Mar 19, 2024
819ef58
Change name of the package
atomyks Mar 25, 2024
979b112
Merge branch 'main' into feature/simulator_py_model
maxime-clem Apr 5, 2024
9ae8046
add cspell:ignore libpython
maxime-clem Apr 5, 2024
b69d968
rename pyin/pyout to py_model_inputs/py_model_outputs
maxime-clem Apr 5, 2024
3b72bc8
rename Pymodel -> PyModel and pymodel -> py_model
maxime-clem Apr 5, 2024
48379dc
add cpell:ignore pymodel
maxime-clem Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions simulator/learning_based_vehicle_model/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.14.4)
project(learning_based_vehicle_model)

find_package(autoware_cmake REQUIRED)
autoware_package()

find_package(Python3 COMPONENTS Interpreter Development)
find_package(pybind11 CONFIG)

ament_auto_add_library(${PROJECT_NAME} SHARED
DIRECTORY src
)
target_link_libraries(${PROJECT_NAME} pybind11::embed ${Python3_LIBRARIES})
target_include_directories(${PROJECT_NAME} PRIVATE ${Python3_INCLUDE_DIRS})

target_compile_options(${PROJECT_NAME} PRIVATE -fvisibility=hidden)

install(
DIRECTORY include/
DESTINATION include/${PROJECT_NAME}
)

ament_auto_package()
208 changes: 208 additions & 0 deletions simulator/learning_based_vehicle_model/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Learned Model

This is the design document for the Python learned model used in the `simple_planning_simulator` package.

## Purpose / Use cases

<!-- Required -->
<!-- Things to consider:
- Why did we implement this feature? -->

This library creates an interface between models in Python and PSIM (C++). It is used to quickly deploy learned Python models in PSIM without a need for complex C++ implementation.

## Design

<!-- Required -->
<!-- Things to consider:
- How does it work? -->

The idea behind this package is that the model we want to use for simulation consists of multiple sub-models (e.g., steering model, drive model, vehicle kinematics, etc.). These sub-models are implemented in Python and can be trainable. Each sub-model has string names for all of its inputs/outputs, which are used to create model interconnections automatically (see image below). This allows us to easily switch sub-models for better customization of the simulator.

![py_model_interface](./image/python_model_interface.png "PyModel interface")

## Assumptions / Known limits

<!-- Required -->

To use this package `python3` and `pybind11` need to be installed. The only assumption on Python sub-models is their interface.

```python
class PythonSubmodelInterface:

def forward(self, action, state): # Required
"""
Calculate forward pass through the model and returns next_state.
"""
return list()

def get_state_names(self): # Required
"""
Return list of string names of the model states (outputs).
"""
return list()

def get_action_names(self): # Required
"""
Return list of string names of the model actions (inputs).
"""
return list()

def reset(self): # Required
"""
Reset model. This function is called after load_params().
"""
pass

def load_params(self, path): # Required
"""
Load parameters of the model.
Inputs:
- path: Path to a parameter file to load by the model.
"""
pass

def dtSet(self, dt): # Required
"""
Set dt of the model.
Inputs:
- dt: time step
"""
pass
```

## API

<!-- Required -->
<!-- Things to consider:
- How do you use the package / API? -->

To successfully create a vehicle model an InterconnectedModel class needs to be set up correctly.

### InterconnectedModel class

#### `Constructor`

The constructor takes no arguments.

#### `void addSubmodel(std::tuple<std::string, std::string, std::string> model_descriptor)`

Add a new sub-model to the model.

Inputs:

- model_descriptor: Describes what model should be used. The model descriptor contains three strings:
- The first string is a path to a python module where the model is implemented.
- The second string is a path to the file where model parameters are stored.
- The third string is the name of the class that implements the model.

Outputs:

- None

#### `void generateConnections(std::vector<char *> in_names, std::vector<char*> out_names)`

Generate connections between sub-models and inputs/outputs of the model.

Inputs:

- in_names: String names for all of the model inputs in order.
- out_names: String names for all of the model outputs in order.

Outputs:

- None

#### `void initState(std::vector<double> new_state)`

Set the initial state of the model.

Inputs:

- new_state: New state of the model.

Outputs:

- None

#### `std::vector<double> updatePyModel(std::vector<double> psim_input)`

Calculate the next state of the model by calculating the next state of all of the sub-models.

Inputs:

- psim_input: Input to the model.

Outputs:

- next_state: Next state of the model.

#### `dtSet(double dt)`

Set the time step of the model.

Inputs:

- dt: time step

Outputs:

- None

### Example

Firstly we need to set up the model.

```C++
InterconnectedModel vehicle;

// Example of model descriptors
std::tuple<char*, char*, char*> model_descriptor_1 = {
(char*)"path_to_python_module_with_model_class_1",
(char*)nullptr, // If no param file is needed you can pass 'nullptr'
(char*)"ModelClass1"
};

std::tuple<char*, char*, char*> model_descriptor_2 = {
(char*)"path_to_python_module_with_model_class_2",
(char*)"/path_to/param_file",
(char*)"ModelClass2" // Name of the python class. Needs to use the interface from 'Assumptions'
};

// Create sub-models based on descriptors
vehicle.addSubmodel(model_descriptor_1);
vehicle.addSubmodel(model_descriptor_2);

// Define STATE and INPUT names of the system
std::vector<char*> state_names = {(char*)"STATE_NAME_1", (char*)"STATE_NAME_2"};
std::vector<char*> input_names = {(char*)"INPUT_NAME_1", (char*)"INPUT_NAME_2"};

// Automatically connect sub-systems with model input
vehicle.generateConnections(input_names, state_names);

// Set the time step of the model
vehicle.dtSet(dt);
```

After the model is correctly set up, we can use it the following way.

```C++
// Example of an model input
std::vector<double> vehicle_input = {0.0, 1.0}; // INPUT_NAME_1, INPUT_NAME_2

// Example of an model state
std::vector<double> current_state = {0.2, 0.5}; // STATE_NAME_1, STATE_NAME_2

// Set model state
vehicle.initState(current_state);

// Calculate the next state of the model
std::vector<double> next_state = vehicle.updatePyModel(vehicle_input);
```

## References / External links

<!-- Optional -->

## Related issues

<!-- Required -->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright 2024 The Autoware Foundation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef LEARNING_BASED_VEHICLE_MODEL__INTERCONNECTED_MODEL_HPP_
#define LEARNING_BASED_VEHICLE_MODEL__INTERCONNECTED_MODEL_HPP_

#include "learning_based_vehicle_model/model_connections_helpers.hpp"
#include "learning_based_vehicle_model/simple_pymodel.hpp"
#include "learning_based_vehicle_model/submodel_interface.hpp"

#include <dlfcn.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>

#include <algorithm>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

namespace py = pybind11;

class __attribute__((visibility("default"))) InterconnectedModel
{
// Vector of unique names of inputs and outputs of sub-models
std::vector<char *> signals_vec_names;
std::vector<double> model_signals_vec;
int num_signals;

std::vector<std::unique_ptr<SubModelInterface>> submodels;

// index in "map_in_to_sig_vec" is index in "py_inputs" and value in "map_in_to_sig_vec" is index
// in "all_variables_names"
std::vector<int> map_in_to_sig_vec;

// index in "map_sig_vec_to_out" is index in "py_model_outputs" and value in "map_sig_vec_to_out"
// is index in "all_variables_names"
std::vector<int> map_sig_vec_to_out;

public:
py::scoped_interpreter guard{}; // start the interpreter and keep it alive

/**
* @brief constructor
*/
InterconnectedModel()
{
// Initialize python library
// cspell:ignore libpython
// Manually load libpython3.10.so as we need it for python.h.
dlopen("libpython3.10.so", RTLD_GLOBAL | RTLD_NOW);
/*
More about the line above here:
https://stackoverflow.com/questions/60719987/embedding-python-which-uses-numpy-in-c-doesnt-work-in-library-dynamically-loa
https://mail.python.org/pipermail/new-bugs-announce/2008-November/003322.html
https://stackoverflow.com/questions/67891197/ctypes-cpython-39-x86-64-linux-gnu-so-undefined-symbol-pyfloat-type-in-embedd
https://man7.org/linux/man-pages/man3/dlopen.3.html
*/
}

private:
/**
* @brief create a mapping between vector of signal input names from PSIM to vector of signals
* @param [in] in_names vector of signal input names from PSIM
*/
void mapInputs(std::vector<char *> in_names);

/**
* @brief create a mapping between vector of signal output names from PSIM to vector of signals
* @param [in] out_names vector of signal output names from PSIM
*/
void mapOutputs(std::vector<char *> out_names);

/**
* @brief add unique names to the vector of signal names
* @param [in] names vector of signal names
*/
void addNamesToSigVec(const std::vector<char *> & names);

/**
* @brief create of signal names from all sub-models and PSIM signal names
*/
void getSignalNames(std::vector<char *> in_names, std::vector<char *> out_names);

public:
/**
* @brief automatically create connections between PSIM and all of the sub-models
* @param [in] in_names string names of inputs available from PSIM
* @param [in] out_names string names of outputs required by PSIM
*/
void generateConnections(std::vector<char *> in_names, std::vector<char *> out_names);

/**
* @brief add a sub-model consisting of base + error model
* @param [in] submodel_desc descriptor of the sub-model
*/
void addSubmodel(std::tuple<std::string, std::string, std::string> submodel_desc);

/**
* @brief set a new model state if it was changed using PSIM interface (mainly position and
* orientation)
* @param [in] new_state new state set by PSIM
*/
void initState(std::vector<double> new_state);

/**
* @brief set time step for all the models
* @param [in] dt time step
*/
void dtSet(double dt);

/**
* @brief compute next step of the PSIM model using python sub-models
* @param [in] psim_input vector of input values provided by PSIM
*/
std::vector<double> updatePyModel(std::vector<double> psim_input);
};

#endif // LEARNING_BASED_VEHICLE_MODEL__INTERCONNECTED_MODEL_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2024 The Autoware Foundation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef LEARNING_BASED_VEHICLE_MODEL__MODEL_CONNECTIONS_HELPERS_HPP_
#define LEARNING_BASED_VEHICLE_MODEL__MODEL_CONNECTIONS_HELPERS_HPP_

#include <cstring>
#include <vector>

std::vector<double> fillVectorUsingMap(
std::vector<double> vector1, std::vector<double> vector2, std::vector<int> map, bool inverse);

std::vector<int> createConnectionsMap(
std::vector<char *> connection_names_1, std::vector<char *> connection_names_2);

#endif // LEARNING_BASED_VEHICLE_MODEL__MODEL_CONNECTIONS_HELPERS_HPP_
Loading
Loading