From cd0446f04b025643555225e1e775a1f9870e8dbe Mon Sep 17 00:00:00 2001 From: domire8 <71256590+domire8@users.noreply.github.com> Date: Fri, 1 Apr 2022 09:22:05 +0200 Subject: [PATCH 1/8] Release 5.1.0 (#272) * v1.0.0-rc1 Add version and experimental features * Add project version 1.0.0 to top level CMakeLists * Use a build option EXPERIMENTAL_FEATURES which can be used to disable experimental features (off by default). * Mark DualQuaternion sources experimental using cmake if (EXPERIMENTAL_FEATURES) * Mark test_dual_quaternion as experimental using preprocessing directive #ifdef EXPERIMENTAL_FEATURES * Remove message lines from CMakeLists * Remove message("experimental") and subsequent second message line from state representation cmakelists, which was only included to test the EXPERIMENTAL_FEATURES flag was working * Update license to Gnu GPL v3 * v2.0.0-rc-02 * Update project version number * Update CHANGELOG * v3.0.0-rc01 * Increment version numbers in C++ and Python projects * Update CHANGELOG * v3.1.0-rc01 * Increment version numbers in C++ and Python projects * Update CHANGELOG * Set version 4.0.0 * Rename control-libraries * Update all references to control_libraries to the new repo name control-libraries * Update CHANGELOG * Update version number * Update CHANGELOG * Set version 5.0.0 * Update CHANGELOG * 5.1.0 -> 5.1.0 * Update CHANGELOG * Update python README * Move new bindings to features section Co-authored-by: Enrico Eberhard Co-authored-by: Enrico Eberhard <32450951+eeberhard@users.noreply.github.com> --- CHANGELOG.md | 28 +++++++++++++---- VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/README.md | 49 ----------------------------- python/setup.py | 2 +- source/CMakeLists.txt | 2 +- 7 files changed, 27 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 564b81d18..e5a3f8ac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG Release Versions: +- [5.1.0](#510) - [5.0.0](#500) - [4.1.0](#410) - [4.0.0](#400) @@ -9,17 +10,32 @@ Release Versions: - [2.0.0](#200) - [1.0.0](#100) -## Upcoming changes (in development) +## 5.1.0 +Version 5.1.0 contains a few new features and improvements to the behaviour and usage of the libraries. + +### Features + +**python** +- Add python bindings for robot model (#263) +- Controllers bindings (#266, #269, #271) + +### Fixes and improvements + +**protocol** +- Add Docker resources for testing and serving for protocol (#267) + +**python** +- Bind ParameterMap (#265, #268) + +**state_representation** +- ParameterInterface accessors to underlying parameters (#256) + +**general** - Incremental versioning (#260) - Refactor cmake to export package (#259, #261) -- ParameterInterface accessors to underlying parameters (#256) - Improve CI checks for pull requests (#262) - Remove previous eigen3 installation (#252, 264) -- Add python bindings for robot model (#263) -- Bind ParameterMap (#265, #268) -- Add Docker resources for testing and serving for protocol (#267) -- Controllers bindings (#266, #269, #271) ## 5.0.0 diff --git a/VERSION b/VERSION index 4b57201ae..831446cbd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.14 +5.1.0 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index 233579799..0f4c7c439 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.0.14 +PROJECT_NUMBER = 5.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index e11b34117..baf440b61 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.0.14) +project(clproto VERSION 5.1.0) set(CMAKE_CXX_STANDARD 17) diff --git a/python/README.md b/python/README.md index c97c453cd..ce47f0ed0 100644 --- a/python/README.md +++ b/python/README.md @@ -70,55 +70,6 @@ encoded_msg = clproto.encode(B, clproto.MessageType.JOINT_STATE_MESSAGE) decoded_object = clproto.decode(encoded_msg) ``` -## Current status - -The Python binding project is currently under development. -Bindings exist for the following modules, classes and methods: - -- `state_representation`: - - `State` - - `StateType` - - `SpatialState` - - `CartesianState` - - `CartesianPose` - - `CartesianTwist` - - `CartesianAcceleration` - - `CartesianWrench` - - `JointState` - - `JointPositions` - - `JointVelocities` - - `JointTorques` - - `Jacobian` - - `Shape` - - `Ellipsoid` - - `Parameter` -- `controllers`: - - -- `dynamical_systems`: - - `DYNAMICAL_SYSTEM` - - `create_cartesian_ds(type)` - - `create_joint_ds(type)` - - `CartesianDefaultDS` - - `CartesianPointAttractorDS` - - `CircularDS` - - `RingDS` - - `JointDefaultDS` - - `JointPointAttractorDS` -- `robot_model`: - - -- `clproto`: - - `MessageType` - - `ParameterMessageType` - - `is_valid(msg)` - - `check_message_type(msg)` - - `check_parameter_message_type(msg)` - - `msg = encode(obj, type)` - - `obj = decode(msg)` - - `pack_fields(encoded_fields)` - - `unpack_fields(packet)` - - `json = to_json(msg)` - - `msg = from_json(json)` - ## About [PyBind11](https://PyBind11.readthedocs.io/en/stable/index.html) is used to generate diff --git a/python/setup.py b/python/setup.py index 37fc82522..86002d3cf 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.0.14" +__version__ = "5.1.0" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 392f1fe1d..547267e21 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.0.14) +project(control_libraries VERSION 5.1.0) # Build options option(BUILD_TESTING "Build all tests." OFF) From 9fe98b4848edd81ffda7fde265cb8870cc038586 Mon Sep 17 00:00:00 2001 From: domire8 <71256590+domire8@users.noreply.github.com> Date: Fri, 1 Apr 2022 12:57:58 +0200 Subject: [PATCH 2/8] Throw exception if setting state variable from vector with wrong size (#273) * Throw exception when setting state variable with wrong vector size * Nicer exception message * 5.1.0 -> 5.1.1 * Update CHANGELOG * Remove unused function * Add unittests --- CHANGELOG.md | 4 +++ VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/setup.py | 2 +- .../space/cartesian/test_cartesian_state.py | 2 ++ source/CMakeLists.txt | 2 +- .../space/cartesian/CartesianState.hpp | 28 ++++--------------- .../space/cartesian/test_cartesian_state.cpp | 1 + 9 files changed, 18 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5a3f8ac6..024e77edf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Release Versions: - [2.0.0](#200) - [1.0.0](#100) +## Upcoming changes (in development) + +- Throw exception if setting state variable from vector with wrong size (#273) + ## 5.1.0 Version 5.1.0 contains a few new features and improvements to the behaviour and usage of the libraries. diff --git a/VERSION b/VERSION index 831446cbd..ac14c3dfa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.0 +5.1.1 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index 0f4c7c439..f22c3a605 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.0 +PROJECT_NUMBER = 5.1.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index baf440b61..2562eaf5b 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.0) +project(clproto VERSION 5.1.1) set(CMAKE_CXX_STANDARD 17) diff --git a/python/setup.py b/python/setup.py index 86002d3cf..3c0df6f4d 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.0" +__version__ = "5.1.1" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/python/test/state_representation/space/cartesian/test_cartesian_state.py b/python/test/state_representation/space/cartesian/test_cartesian_state.py index 289697682..262c55f84 100755 --- a/python/test/state_representation/space/cartesian/test_cartesian_state.py +++ b/python/test/state_representation/space/cartesian/test_cartesian_state.py @@ -185,6 +185,8 @@ def test_get_set_fields(self): [self.assertAlmostEqual(cs.get_position()[i], position[i]) for i in range(3)] cs.set_position(1.1, 2.2, 3.3) assert_array_equal(np.array([1.1, 2.2, 3.3]), cs.get_position()) + with self.assertRaises(RuntimeError): + cs.set_position([1., 2., 3., 4.]) # orientation orientation_vec = np.random.rand(4) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 547267e21..6c57c68bf 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.0) +project(control_libraries VERSION 5.1.1) # Build options option(BUILD_TESTING "Build all tests." OFF) diff --git a/source/state_representation/include/state_representation/space/cartesian/CartesianState.hpp b/source/state_representation/include/state_representation/space/cartesian/CartesianState.hpp index ba64d3ec6..65aea975b 100644 --- a/source/state_representation/include/state_representation/space/cartesian/CartesianState.hpp +++ b/source/state_representation/include/state_representation/space/cartesian/CartesianState.hpp @@ -86,17 +86,6 @@ class CartesianState : public SpatialState { const Eigen::Matrix& new_value ); - /** - * @brief Set new_value in the provided state_variable (twist, acceleration or wrench) - * @param linear_state_variable the linear part of the state variable to fill - * @param angular_state_variable the angular part of the state variable to fill - * @param new_value the new value of the state variable - */ - void set_state_variable( - Eigen::Vector3d& linear_state_variable, Eigen::Vector3d& angular_state_variable, - const std::vector& new_value - ); - protected: /** * @brief Getter of the variable value corresponding to the input @@ -557,8 +546,7 @@ inline const Eigen::Quaterniond& CartesianState::get_orientation() const { inline Eigen::Vector4d CartesianState::get_orientation_coefficients() const { return Eigen::Vector4d( this->get_orientation().w(), this->get_orientation().x(), this->get_orientation().y(), - this->get_orientation().z() - ); + this->get_orientation().z()); } inline Eigen::Matrix CartesianState::get_pose() const { @@ -664,7 +652,7 @@ inline Eigen::VectorXd CartesianState::get_state_variable(const CartesianStateVa inline void CartesianState::set_all_state_variables(const Eigen::VectorXd& new_values) { if (new_values.size() != 25) { - throw state_representation::exceptions::IncompatibleSizeException( + throw exceptions::IncompatibleSizeException( "Input is of incorrect size: expected 25, given " + std::to_string(new_values.size())); } this->set_pose(new_values.segment(0, 7)); @@ -679,6 +667,10 @@ inline void CartesianState::set_state_variable(Eigen::Vector3d& state_variable, } inline void CartesianState::set_state_variable(Eigen::Vector3d& state_variable, const std::vector& new_value) { + if (new_value.size() != 3) { + throw exceptions::IncompatibleSizeException( + "Input vector is of incorrect size: expected 3, given " + std::to_string(new_value.size())); + } this->set_state_variable(state_variable, Eigen::Vector3d::Map(new_value.data(), new_value.size())); } @@ -690,14 +682,6 @@ inline void CartesianState::set_state_variable( this->set_state_variable(angular_state_variable, new_value.tail(3)); } -inline void CartesianState::set_state_variable( - Eigen::Vector3d& linear_state_variable, Eigen::Vector3d& angular_state_variable, - const std::vector& new_value -) { - this->set_state_variable(linear_state_variable, std::vector(new_value.begin(), new_value.begin() + 3)); - this->set_state_variable(angular_state_variable, std::vector(new_value.begin() + 3, new_value.end())); -} - inline void CartesianState::set_position(const Eigen::Vector3d& position) { this->set_state_variable(this->position_, position); } diff --git a/source/state_representation/test/tests/space/cartesian/test_cartesian_state.cpp b/source/state_representation/test/tests/space/cartesian/test_cartesian_state.cpp index 8e99fb564..2773610ad 100644 --- a/source/state_representation/test/tests/space/cartesian/test_cartesian_state.cpp +++ b/source/state_representation/test/tests/space/cartesian/test_cartesian_state.cpp @@ -119,6 +119,7 @@ TEST(CartesianStateTest, GetSetFields) { } cs.set_position(1.1, 2.2, 3.3); EXPECT_TRUE(Eigen::Vector3d(1.1, 2.2, 3.3).isApprox(cs.get_position())); + EXPECT_THROW(cs.set_position(std::vector{1, 2, 3, 4}), exceptions::IncompatibleSizeException); // orientation Eigen::Vector4d orientation_vec = Eigen::Vector4d::Random().normalized(); From 90ed7cee677ea497160fae5783d4140d82ec4021 Mon Sep 17 00:00:00 2001 From: Enrico Eberhard <32450951+eeberhard@users.noreply.github.com> Date: Fri, 1 Apr 2022 16:00:10 +0200 Subject: [PATCH 3/8] Improve installation script and guide (#274) * Remove ./tmp folder before installation * Add -p to mkdir in eigen installation * Improve clarity in install guide * Update python installation guide * 5.1.1 -> 5.1.2 * Changelog --- CHANGELOG.md | 1 + VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/README.md | 10 ++++++++-- python/setup.py | 2 +- source/CMakeLists.txt | 2 +- source/install.sh | 5 ++++- 8 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 024e77edf..5a1bc581e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Release Versions: ## Upcoming changes (in development) - Throw exception if setting state variable from vector with wrong size (#273) +- Improve installation script and python installation guide (#274) ## 5.1.0 diff --git a/VERSION b/VERSION index ac14c3dfa..61fcc8735 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.1 +5.1.2 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index f22c3a605..d213e9751 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.1 +PROJECT_NUMBER = 5.1.2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index 2562eaf5b..be7514aed 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.1) +project(clproto VERSION 5.1.2) set(CMAKE_CXX_STANDARD 17) diff --git a/python/README.md b/python/README.md index ce47f0ed0..aa33660ff 100644 --- a/python/README.md +++ b/python/README.md @@ -12,13 +12,19 @@ Additionally, the installation of the bindings requires the following prerequisi - `pip3` >= 10.0.0 The installation itself is then quite straightforward: -```shell script +```shell git clone https://github.com/epfl-lasa/control-libraries ## install control-libraries (skip this stage if already done) -bash control-libraries/source/install.sh +sudo control-libraries/source/install.sh ## install the bindings using the pip installer +pip3 install control-libraries/python +``` + +If the installation fails, it may be because of non-default installation directories for some dependencies. +In this case, the include path for OSQP and OpenRobots can be set through environment variables before the pip install. +```shell export OSQP_INCLUDE_DIR='/path/to/include/osqp' # default /usr/local/include/osqp export OPENROBOTS_INCLUDE_DIR='/path/to/openrobots/include' # default /opt/openrobots/include pip3 install control-libraries/python diff --git a/python/setup.py b/python/setup.py index 3c0df6f4d..b7a97348c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.1" +__version__ = "5.1.2" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 6c57c68bf..88039eee0 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.1) +project(control_libraries VERSION 5.1.2) # Build options option(BUILD_TESTING "Build all tests." OFF) diff --git a/source/install.sh b/source/install.sh index 61ed93d78..86aaeeefa 100755 --- a/source/install.sh +++ b/source/install.sh @@ -79,13 +79,16 @@ if [ "${BUILD_CONTROLLERS}" == "ON" ] && [ "${BUILD_ROBOT_MODEL}" == "OFF" ]; th exit 1 fi +# cleanup any previous build folders +rm -rf "${SOURCE_PATH}"/tmp + # install base dependencies echo ">>> INSTALLING BASE DEPENDENCIES" INSTALLED_EIGEN=$(pkg-config --modversion eigen3) if [ "${INSTALLED_EIGEN::4}" != "${EIGEN_VERSION::4}" ]; then mkdir -p "${SOURCE_PATH}"/tmp/lib && cd "${SOURCE_PATH}"/tmp/lib || exit 1 wget -c "https://gitlab.com/libeigen/eigen/-/archive/${EIGEN_VERSION}/eigen-${EIGEN_VERSION}.tar.gz" -O - | tar -xz || exit 1 - cd "eigen-${EIGEN_VERSION}" && mkdir build && cd build && cmake .. && make install || exit 1 + cd "eigen-${EIGEN_VERSION}" && mkdir -p build && cd build && cmake .. && make install || exit 1 fi EIGEN_PATH=$(cmake --find-package -DNAME=Eigen3 -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=COMPILE) if [ "${EIGEN_PATH::14}" != "-I/usr/include" ]; then From 99331fe60da5fdbe59d5ac2b7f8b7fd9c92efc54 Mon Sep 17 00:00:00 2001 From: Alberic de Lajarte <42264772+AlbericLaj@users.noreply.github.com> Date: Tue, 5 Apr 2022 09:54:43 +0200 Subject: [PATCH 4/8] Fix path in protocol installation guide (#275) * Fix path in proto installation guide * Update changelog * 5.1.2 -> 5.1.3 Co-authored-by: Michael Co-authored-by: Enrico Eberhard --- CHANGELOG.md | 1 + VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/README.md | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/setup.py | 2 +- source/CMakeLists.txt | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1bc581e..11fdd825d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Release Versions: - Throw exception if setting state variable from vector with wrong size (#273) - Improve installation script and python installation guide (#274) +- Fix path in protocol installation guide (#275) ## 5.1.0 diff --git a/VERSION b/VERSION index 61fcc8735..cdb98d26e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.2 +5.1.3 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index d213e9751..b3340a82d 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.2 +PROJECT_NUMBER = 5.1.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/README.md b/protocol/README.md index 900fb9f60..adebc5378 100644 --- a/protocol/README.md +++ b/protocol/README.md @@ -34,7 +34,7 @@ By supplying the `--auto` flag to this script, it will automatically and recursi If Protobuf is not yet installed, this step will take some time. ```shell git clone https://github.com/epfl-lasa/control-libraries.git -sudo control-libraries/clproto/install.sh --auto +sudo control-libraries/protocol/install.sh --auto ``` ### Copying protobuf dependencies diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index be7514aed..43d9baa98 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.2) +project(clproto VERSION 5.1.3) set(CMAKE_CXX_STANDARD 17) diff --git a/python/setup.py b/python/setup.py index b7a97348c..6eaef4e5f 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.2" +__version__ = "5.1.3" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 88039eee0..866ecf216 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.2) +project(control_libraries VERSION 5.1.3) # Build options option(BUILD_TESTING "Build all tests." OFF) From 2ed787143bb316d78dc4e50458b8212e0228d20c Mon Sep 17 00:00:00 2001 From: Enrico Eberhard <32450951+eeberhard@users.noreply.github.com> Date: Wed, 6 Apr 2022 10:53:05 +0200 Subject: [PATCH 5/8] Add force limit to impedance controller (#276) * Add a parameter for force limit that is a maximum absolute value for each degree of freedom * Implement parameter validation that allows the force limit to be set from a double or vector * Clamp to the force limit after computing the command * Update test to check limit behaviour * Changelog * 5.1.3 -> 5.1.4 --- CHANGELOG.md | 1 + VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/setup.py | 2 +- source/CMakeLists.txt | 2 +- .../controllers/impedance/Impedance.hpp | 24 +++++- .../controllers/src/impedance/Impedance.cpp | 10 ++- .../controllers/test/tests/test_impedance.cpp | 82 ++++++++++++++++++- 9 files changed, 117 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11fdd825d..2263c2791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Release Versions: - Throw exception if setting state variable from vector with wrong size (#273) - Improve installation script and python installation guide (#274) - Fix path in protocol installation guide (#275) +- Add force limit parameter to Impedance controller (#276) ## 5.1.0 diff --git a/VERSION b/VERSION index cdb98d26e..76e9e619d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.3 +5.1.4 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index b3340a82d..49047c382 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.3 +PROJECT_NUMBER = 5.1.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index 43d9baa98..4b1ed81a3 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.3) +project(clproto VERSION 5.1.4) set(CMAKE_CXX_STANDARD 17) diff --git a/python/setup.py b/python/setup.py index 6eaef4e5f..231b7bc86 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.3" +__version__ = "5.1.4" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 866ecf216..48a102d5b 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.3) +project(control_libraries VERSION 5.1.4) # Build options option(BUILD_TESTING "Build all tests." OFF) diff --git a/source/controllers/include/controllers/impedance/Impedance.hpp b/source/controllers/include/controllers/impedance/Impedance.hpp index 30a8f6350..02bee783c 100644 --- a/source/controllers/include/controllers/impedance/Impedance.hpp +++ b/source/controllers/include/controllers/impedance/Impedance.hpp @@ -42,6 +42,8 @@ class Impedance : public IController { protected: + void clamp_force(Eigen::VectorXd& force); + /** * @brief Validate and set parameters for damping, stiffness and inertia gain matrices. * @param parameter A parameter interface pointer @@ -62,8 +64,10 @@ class Impedance : public IController { damping_; ///< damping matrix of the controller associated to velocity std::shared_ptr> inertia_; ///< inertia matrix of the controller associated to acceleration + std::shared_ptr> + force_limit_; ///< vector of force limits for each degree of freedom - const unsigned int dimensions_; ///< dimensionality of the control space and associated gain matricess + const unsigned int dimensions_; ///< dimensionality of the control space and associated gain matrices }; template @@ -74,10 +78,13 @@ Impedance::Impedance(unsigned int dimensions) : state_representation::make_shared_parameter( "damping", Eigen::MatrixXd::Identity(dimensions, dimensions))), inertia_( state_representation::make_shared_parameter( - "inertia", Eigen::MatrixXd::Identity(dimensions, dimensions))), dimensions_(dimensions) { + "inertia", Eigen::MatrixXd::Identity(dimensions, dimensions))), force_limit_( + state_representation::make_shared_parameter( + "force_limit", Eigen::VectorXd::Zero(dimensions))), dimensions_(dimensions) { this->parameters_.insert(std::make_pair("stiffness", stiffness_)); this->parameters_.insert(std::make_pair("damping", damping_)); this->parameters_.insert(std::make_pair("inertia", inertia_)); + this->parameters_.insert(std::make_pair("force_limit", inertia_)); } template @@ -88,6 +95,16 @@ Impedance::Impedance( this->set_parameters(parameters); } +template +void Impedance::clamp_force(Eigen::VectorXd& force) { + auto limit = this->force_limit_->get_value(); + for (std::size_t index = 0; index < this->dimensions_; ++index) { + if (limit(index) > 0.0 && abs(force(index)) > limit(index)) { + force(index) = force(index) > 0.0 ? limit(index) : -limit(index); + } + } +} + template void Impedance::validate_and_set_parameter( const std::shared_ptr& parameter @@ -98,6 +115,9 @@ void Impedance::validate_and_set_parameter( this->damping_->set_value(this->gain_matrix_from_parameter(parameter)); } else if (parameter->get_name() == "inertia") { this->inertia_->set_value(this->gain_matrix_from_parameter(parameter)); + } else if (parameter->get_name() == "force_limit") { + auto limit_matrix = this->gain_matrix_from_parameter(parameter); + this->force_limit_->set_value(limit_matrix.diagonal()); } } diff --git a/source/controllers/src/impedance/Impedance.cpp b/source/controllers/src/impedance/Impedance.cpp index db494bd50..cd6678313 100644 --- a/source/controllers/src/impedance/Impedance.cpp +++ b/source/controllers/src/impedance/Impedance.cpp @@ -25,14 +25,19 @@ CartesianState Impedance::compute_command( + this->damping_->get_value().topLeftCorner<3, 3>() * state_error.get_linear_velocity() + this->inertia_->get_value().topLeftCorner<3, 3>() * command_state.get_linear_acceleration(); Eigen::Vector3d commanded_force = position_control + state_error.get_force(); - command.set_force(commanded_force); + // compute torque (orientation requires special care) Eigen::Vector3d orientation_control = this->stiffness_->get_value().bottomRightCorner<3, 3>() * state_error.get_orientation().vec() + this->damping_->get_value().bottomRightCorner<3, 3>() * state_error.get_angular_velocity() + this->inertia_->get_value().bottomRightCorner<3, 3>() * command_state.get_angular_acceleration(); Eigen::Vector3d commanded_torque = orientation_control + state_error.get_torque(); - command.set_torque(commanded_torque); + + Eigen::VectorXd wrench(6); + wrench << commanded_force, commanded_torque; + clamp_force(wrench); + + command.set_wrench(wrench); return command; } @@ -48,6 +53,7 @@ JointState Impedance::compute_command( + this->damping_->get_value() * state_error.get_velocities() + this->inertia_->get_value() * command_state.get_accelerations(); Eigen::VectorXd commanded_torques = state_control + state_error.get_torques(); + clamp_force(commanded_torques); command.set_torques(commanded_torques); return command; } diff --git a/source/controllers/test/tests/test_impedance.cpp b/source/controllers/test/tests/test_impedance.cpp index d7bfaa9d1..0e7d76d39 100644 --- a/source/controllers/test/tests/test_impedance.cpp +++ b/source/controllers/test/tests/test_impedance.cpp @@ -9,7 +9,6 @@ #include "state_representation/space/cartesian/CartesianState.hpp" #include "state_representation/space/cartesian/CartesianWrench.hpp" - using namespace controllers; using namespace state_representation; @@ -29,6 +28,46 @@ TEST(ImpedanceControllerTest, TestCartesianImpedance) { EXPECT_TRUE(command.data().norm() > 0.); } +TEST(ImpedanceControllerTest, TestCartesianImpedanceLimits) { + auto controller = CartesianControllerFactory::create_controller(CONTROLLER_TYPE::IMPEDANCE); + + auto desired_state = CartesianState::Identity("test"); + auto feedback_state = desired_state; + + Eigen::VectorXd twist(6); + twist << 1.0, -2.0, 3.0, -4.0, 5.0, -6.0; + feedback_state.set_twist(twist); + + // with default unit gains, expect some equivalent response data + CartesianWrench command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < 6; ++index) { + EXPECT_NEAR(abs(command.data()(index)), abs(twist(index)), 1e-6); + } + + // set a scalar force limit + double limit = 1.0; + EXPECT_NO_THROW(controller->set_parameter_value("force_limit", limit)); + // expect all degrees of freedom to have the same force limit + command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < 6; ++index) { + EXPECT_LE(abs(command.data()(index)), limit); + } + + // set a force limit on each degree of freedom + std::vector limits = {0.5, 1.0, 1.5, 2.0, 3.5, 4.0}; + EXPECT_NO_THROW(controller->set_parameter_value("force_limit", limits)); + + // expect all degrees of freedom to respect the individual force limits + command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < 6; ++index) { + EXPECT_LE(abs(command.data()(index)), limits.at(index)); + } + + // ensure the limit must match the degrees of freedom + EXPECT_THROW(controller->set_parameter_value("force_limit", std::vector({1.0, 2.0})), + state_representation::exceptions::IncompatibleSizeException); +} + TEST(ImpedanceControllerTest, TestJointImpedance) { int nb_joints = 3; auto controller = JointControllerFactory::create_controller(CONTROLLER_TYPE::IMPEDANCE, nb_joints); @@ -46,6 +85,47 @@ TEST(ImpedanceControllerTest, TestJointImpedance) { EXPECT_TRUE(command.data().norm() > 0.); } +TEST(ImpedanceControllerTest, TestJointImpedanceLimits) { + int nb_joints = 3; + auto controller = JointControllerFactory::create_controller(CONTROLLER_TYPE::IMPEDANCE, nb_joints); + + auto desired_state = JointState::Zero("test", nb_joints); + auto feedback_state = desired_state; + + Eigen::VectorXd positions(3); + positions << 1.0, -2.0, 3.0; + feedback_state.set_positions(positions); + + // with default unit gains, expect some equivalent response data + JointTorques command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < nb_joints; ++index) { + EXPECT_NEAR(abs(command.data()(index)), abs(positions(index)), 1e-6); + } + + // set a scalar force limit + double limit = 1.0; + EXPECT_NO_THROW(controller->set_parameter_value("force_limit", limit)); + // expect all degrees of freedom to have the same force limit + command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < nb_joints; ++index) { + EXPECT_LE(abs(command.data()(index)), limit); + } + + // set a force limit on each degree of freedom + std::vector limits = {0.5, 1.0, 1.5}; + EXPECT_NO_THROW(controller->set_parameter_value("force_limit", limits)); + + // expect all degrees of freedom to respect the individual force limits + command = controller->compute_command(desired_state, feedback_state); + for (int index = 0; index < nb_joints; ++index) { + EXPECT_LE(abs(command.data()(index)), limits.at(index)); + } + + // ensure the limit must match the degrees of freedom + EXPECT_THROW(controller->set_parameter_value("force_limit", std::vector({1.0, 2.0})), + state_representation::exceptions::IncompatibleSizeException); +} + TEST(ImpedanceControllerTest, TestCartesianToJointImpedance) { auto controller = CartesianControllerFactory::create_controller(CONTROLLER_TYPE::IMPEDANCE); From ee63efb28440a93fc001d5262c06e5fb3701b180 Mon Sep 17 00:00:00 2001 From: domire8 <71256590+domire8@users.noreply.github.com> Date: Fri, 8 Apr 2022 16:57:33 +0200 Subject: [PATCH 6/8] Fix python bindings import issues (#279) * Import modules from state representation correctly * 5.1.4 -> 5.1.5 * Update CHANGELOG --- CHANGELOG.md | 1 + VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/setup.py | 2 +- python/source/controllers/bind_cartesian_controllers.cpp | 3 ++- python/source/controllers/bind_joint_controllers.cpp | 3 ++- python/source/controllers/controllers_bindings.cpp | 2 ++ python/source/dynamical_systems/bind_cartesian.cpp | 3 ++- python/source/dynamical_systems/bind_joint.cpp | 3 ++- python/source/dynamical_systems/dynamical_systems_bindings.cpp | 2 ++ source/CMakeLists.txt | 2 +- 12 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2263c2791..d6c10d9fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Release Versions: - Improve installation script and python installation guide (#274) - Fix path in protocol installation guide (#275) - Add force limit parameter to Impedance controller (#276) +- Fix python bindings import issues (#279) ## 5.1.0 diff --git a/VERSION b/VERSION index 76e9e619d..220d8e0a4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.4 +5.1.5 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index 49047c382..82fe0b145 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.4 +PROJECT_NUMBER = 5.1.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index 4b1ed81a3..80856b732 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.4) +project(clproto VERSION 5.1.5) set(CMAKE_CXX_STANDARD 17) diff --git a/python/setup.py b/python/setup.py index 231b7bc86..27bd82706 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.4" +__version__ = "5.1.5" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/python/source/controllers/bind_cartesian_controllers.cpp b/python/source/controllers/bind_cartesian_controllers.cpp index 174ef7bb8..74b5583c3 100644 --- a/python/source/controllers/bind_cartesian_controllers.cpp +++ b/python/source/controllers/bind_cartesian_controllers.cpp @@ -14,7 +14,8 @@ using namespace state_representation; using namespace py_parameter; void cartesian_controller(py::module_& m) { - py::class_, std::shared_ptr>, ParameterMap, PyController> c(m, "ICartesianController"); + py::object parameter_map = py::module_::import("state_representation").attr("ParameterMap"); + py::class_, std::shared_ptr>, PyController> c(m, "ICartesianController", parameter_map); c.def( "compute_command", py::overload_cast(&IController::compute_command), diff --git a/python/source/controllers/bind_joint_controllers.cpp b/python/source/controllers/bind_joint_controllers.cpp index de59fd6ea..253259a30 100644 --- a/python/source/controllers/bind_joint_controllers.cpp +++ b/python/source/controllers/bind_joint_controllers.cpp @@ -11,7 +11,8 @@ using namespace state_representation; using namespace py_parameter; void joint_controller(py::module_& m) { - py::class_, std::shared_ptr>, ParameterMap, PyController> c(m, "IJointController"); + py::object parameter_map = py::module_::import("state_representation").attr("ParameterMap"); + py::class_, std::shared_ptr>, PyController> c(m, "IJointController", parameter_map); c.def( "compute_command", py::overload_cast(&IController::compute_command), diff --git a/python/source/controllers/controllers_bindings.cpp b/python/source/controllers/controllers_bindings.cpp index 1cafd0ff2..40841efe1 100644 --- a/python/source/controllers/controllers_bindings.cpp +++ b/python/source/controllers/controllers_bindings.cpp @@ -12,6 +12,8 @@ PYBIND11_MODULE(controllers, m) { m.attr("__version__") = "dev"; #endif + py::module_::import("state_representation"); + bind_type(m); bind_computational_space(m); bind_cartesian_controllers(m); diff --git a/python/source/dynamical_systems/bind_cartesian.cpp b/python/source/dynamical_systems/bind_cartesian.cpp index 27b9e3f66..8c0c1d300 100644 --- a/python/source/dynamical_systems/bind_cartesian.cpp +++ b/python/source/dynamical_systems/bind_cartesian.cpp @@ -13,7 +13,8 @@ using namespace state_representation; void cartesian(py::module_& m) { - py::class_, std::shared_ptr>, ParameterMap, PyDynamicalSystem> c(m, "ICartesianDS"); + py::object parameter_map = py::module_::import("state_representation").attr("ParameterMap"); + py::class_, std::shared_ptr>, PyDynamicalSystem> c(m, "ICartesianDS", parameter_map); c.def(py::init<>()); diff --git a/python/source/dynamical_systems/bind_joint.cpp b/python/source/dynamical_systems/bind_joint.cpp index 43090118d..5283235b1 100644 --- a/python/source/dynamical_systems/bind_joint.cpp +++ b/python/source/dynamical_systems/bind_joint.cpp @@ -11,7 +11,8 @@ using namespace state_representation; void joint(py::module_& m) { - py::class_, std::shared_ptr>, ParameterMap, PyDynamicalSystem> c(m, "IJointDS"); + py::object parameter_map = py::module_::import("state_representation").attr("ParameterMap"); + py::class_, std::shared_ptr>, PyDynamicalSystem> c(m, "IJointDS", parameter_map); c.def(py::init<>()); diff --git a/python/source/dynamical_systems/dynamical_systems_bindings.cpp b/python/source/dynamical_systems/dynamical_systems_bindings.cpp index 3ebf786c7..5b852bba6 100644 --- a/python/source/dynamical_systems/dynamical_systems_bindings.cpp +++ b/python/source/dynamical_systems/dynamical_systems_bindings.cpp @@ -12,6 +12,8 @@ PYBIND11_MODULE(dynamical_systems, m) { m.attr("__version__") = "dev"; #endif + py::module_::import("state_representation"); + bind_type(m); bind_cartesian(m); bind_joint(m); diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 48a102d5b..db5d71c6a 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.4) +project(control_libraries VERSION 5.1.5) # Build options option(BUILD_TESTING "Build all tests." OFF) From 5b097b9cfcab557421757e5a25f7d500bae5229a Mon Sep 17 00:00:00 2001 From: Dominic Reber Date: Fri, 8 Apr 2022 17:13:46 +0200 Subject: [PATCH 7/8] Set version 5.2.0 --- VERSION | 2 +- doxygen/doxygen.conf | 2 +- protocol/clproto_cpp/CMakeLists.txt | 2 +- python/setup.py | 2 +- source/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 220d8e0a4..91ff57278 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.5 +5.2.0 diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index 82fe0b145..16e0b0ef3 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "Control Libraries" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.5 +PROJECT_NUMBER = 5.2.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/protocol/clproto_cpp/CMakeLists.txt b/protocol/clproto_cpp/CMakeLists.txt index 80856b732..81b9e7445 100644 --- a/protocol/clproto_cpp/CMakeLists.txt +++ b/protocol/clproto_cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.9) -project(clproto VERSION 5.1.5) +project(clproto VERSION 5.2.0) set(CMAKE_CXX_STANDARD 17) diff --git a/python/setup.py b/python/setup.py index 27bd82706..49b1536e2 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ osqp_path_var = 'OSQP_INCLUDE_DIR' openrobots_path_var = 'OPENROBOTS_INCLUDE_DIR' -__version__ = "5.1.5" +__version__ = "5.2.0" __libraries__ = ['state_representation', 'clproto', 'controllers', 'dynamical_systems', 'robot_model'] __include_dirs__ = ['include'] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index db5d71c6a..e784fd7aa 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(control_libraries VERSION 5.1.5) +project(control_libraries VERSION 5.2.0) # Build options option(BUILD_TESTING "Build all tests." OFF) From e9412f3fd1d8aedf645434ce5a747c23af7ef38e Mon Sep 17 00:00:00 2001 From: Dominic Reber Date: Fri, 8 Apr 2022 17:21:55 +0200 Subject: [PATCH 8/8] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6c10d9fa..696412334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG Release Versions: +- [5.2.0](#520) - [5.1.0](#510) - [5.0.0](#500) - [4.1.0](#410) @@ -10,12 +11,21 @@ Release Versions: - [2.0.0](#200) - [1.0.0](#100) -## Upcoming changes (in development) +## 5.2.0 +Version 5.2.0 contains a few fixes and a new feature for the Impedance controller. + +### Features + +**controllers** +- Add force limit parameter to Impedance controller (#276) + +### Fixes + +**general** - Throw exception if setting state variable from vector with wrong size (#273) - Improve installation script and python installation guide (#274) - Fix path in protocol installation guide (#275) -- Add force limit parameter to Impedance controller (#276) - Fix python bindings import issues (#279) ## 5.1.0