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

Add the LFController unit tests #46

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
3ae60ce
[lf_controller] Add dummy initial unittest for the LF Controller
ArthurVal Dec 11, 2024
3411e2b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 11, 2024
9bb4851
[lf_controller] Add Ctor test
ArthurVal Dec 16, 2024
2dd175c
[lf_controller] Add Init with empty model test
ArthurVal Dec 16, 2024
71c4dcb
[lf_controller] Add Init with nullptr test
ArthurVal Dec 16, 2024
a5fb97e
[lf_controller] Comment out EXAMPLE_ROBOT_DATA_MODEL_DIR
ArthurVal Dec 16, 2024
8e57ee4
[lf_controller] Define test fixture (empty for now)
ArthurVal Dec 18, 2024
3090752
[lf_controller] Add unit test for .initialize() with valid model
ArthurVal Dec 19, 2024
0e4a8e8
[lf_controller] Rename utils/file to file_operation
ArthurVal Dec 19, 2024
af2cc97
[lf_controller] Add FileToString from filesystem::path directly
ArthurVal Dec 19, 2024
fff3c54
[lf_controller] Refactor out talos'reduced file path into a function
ArthurVal Dec 19, 2024
c0a4331
[lf_controller] Add ComputeControlNotInitialized unit test
ArthurVal Dec 19, 2024
8be4dbe
[lf_controller] Add ComputeControlNoInput test
ArthurVal Dec 19, 2024
b8b0af5
[lf_controller] Fix missing EXAMPLE_ROBOT..._DIR definition
ArthurVal Dec 20, 2024
0a16c43
[lf_controller] Minor format updates
ArthurVal Jan 7, 2025
2010a10
[lf_controller] Use fixture with static talos urdf string
ArthurVal Jan 7, 2025
cb13cdc
[lf_controller] Add som template TBD for compute control tests
ArthurVal Jan 7, 2025
ba9e6d4
[lf_controller] Update inline doc of FileOpen
ArthurVal Jan 8, 2025
590e839
[lf_controller] Move using ::Eigen stuff on top of src file
ArthurVal Jan 8, 2025
9d49491
[lf_controller] Rename ComputeControlValid to ComputeControl
ArthurVal Jan 8, 2025
9e9b9a7
[lf_controller] Rename IsJointType* function to Is*
ArthurVal Jan 9, 2025
4d6ef41
[lf_controller] Add the MakeValidRandom* functions (still WIP)
ArthurVal Jan 10, 2025
9cb7ec0
[lf_controller] Default VectorPrintFormat inside struct directly
ArthurVal Jan 10, 2025
463ec79
[lf_controller] Use simplified URDF + Add eigen_conv helper
ArthurVal Jan 10, 2025
9fadb46
[lf_controller] Update the UnknownJoints test
ArthurVal Jan 10, 2025
fa4fa02
[lf_controller] Add Grow() to eigen utils
ArthurVal Jan 13, 2025
aef647a
[lf_controller] Add PushNewJointState function to utils
ArthurVal Jan 13, 2025
332796b
[lf_controller] Implement a SizeMismatch test (on sensor)
ArthurVal Jan 13, 2025
e707f4e
[lf_controller] Add missing MakeRandomControlForJoints inline doc
ArthurVal Jan 13, 2025
47bc072
[lf_controller] Remove pedantic ';'
ArthurVal Jan 13, 2025
4d3478b
[lf_controller] Add a UnaryOp getter to Make* functions
ArthurVal Jan 14, 2025
4f33f62
[tests] Add Grow for Eigen Matrices (NUmDimensions = 2)
ArthurVal Jan 15, 2025
0ddd46c
[lf_controller] Refactor the tests with parameters
ArthurVal Jan 15, 2025
d9e43b6
[lf_controller] Remove ternary operator
ArthurVal Jan 15, 2025
d24269c
[tests] Update Mutation with nodiscard and friend PrintTo
ArthurVal Jan 15, 2025
d323484
[lf_controller] Add ComputeControlSpecialDouble test
ArthurVal Jan 15, 2025
28d0bbd
[lf_controller] Remove SCOPE_TRACE from SpecialDouble tests
ArthurVal Jan 15, 2025
fde8554
[tests] Remove utils/array & utils/file_operation (not used)
ArthurVal Jan 15, 2025
c37c6b1
[lf_controller] Fix the size issues with free flyer tests
ArthurVal Jan 15, 2025
99b399c
[lf_controller] Disable the SpecialDouble test
ArthurVal Jan 15, 2025
e0c4838
[lf_controller] Remove un-used headers
ArthurVal Jan 15, 2025
eac4e70
[lf_controller] Clean up the expected_control (still WIP)
ArthurVal Jan 15, 2025
0e8622c
[tests] Update print_to with meta functions + fix TryToPrintTo API
ArthurVal Jan 16, 2025
1f33867
[lf_controller] Refactor to use ModelDescription as Test params
ArthurVal Jan 17, 2025
3b323f2
[lf_controller] Update the Valid ComputeControl test
ArthurVal Jan 20, 2025
758fba3
[test utils] Change the Eigen Vector PrintTo default strip
ArthurVal Jan 20, 2025
ddcf5b0
[lf_controller] Move Make* LFController function into utils/
ArthurVal Jan 20, 2025
1a998db
[lf_controller] Update to cleaner Push* implementation
ArthurVal Jan 20, 2025
d625e6a
[lf_controller] Fix wrong_control feedforward vs feedback_gains
ArthurVal Jan 20, 2025
e3d6482
[lf_controller] MakeRobotModelBuilderFrom use 'const ref'
ArthurVal Jan 20, 2025
1de6d9e
[utils] Fix std::is_base_of<> usage
ArthurVal Jan 20, 2025
8f2c6ef
[lf_controller] Remove View and ModelDescr template stuff
ArthurVal Jan 21, 2025
bf2e2b5
[utils] Fix internale doc/comment of ConcatenateAs
ArthurVal Jan 21, 2025
ea21689
[utils] Fix wrong MakeAllModelDescription documentation
ArthurVal Jan 21, 2025
efb8c80
[lf_controller] Add JointState size mismatch test for control x_0
ArthurVal Jan 22, 2025
b5a5149
[lf_controller] Remove unused commented index prints
ArthurVal Jan 22, 2025
3c677f1
[utils] Refactor out the init statement of the if(...) for RMB
ArthurVal Jan 30, 2025
fc9e52b
[utils] Replace #pragma once with header guards
ArthurVal Jan 30, 2025
554d46d
[utils] Remove the ConcatenateAs function
ArthurVal Jan 30, 2025
2b3def1
[lf_controller] Refactor expected computation into utils/
ArthurVal Jan 27, 2025
2049ffe
[lf_controller] Fix the error computation (using pinocchio)
ArthurVal Jan 30, 2025
7b939b7
[lf_controller] Fix wrong inline doc
ArthurVal Jan 31, 2025
7200daa
[lf_controller] Fix missing doc for ExpectedLFControllerFrom
ArthurVal Jan 31, 2025
80dac66
[lf_controller] Refactor ExpectedLFControllerFrom args order
ArthurVal Jan 31, 2025
ad767dc
[lf_controller] Remove irrelevant TODO comment
ArthurVal Feb 4, 2025
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
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ if(BUILD_TESTING)

ament_auto_add_gtest(test_pd_controller tests/test_pd_controller.cpp)
target_link_libraries(test_pd_controller ${PROJECT_NAME})

ament_auto_add_gtest(test_lf_controller tests/test_lf_controller.cpp)
target_link_libraries(test_lf_controller ${PROJECT_NAME})
endif()

#
Expand Down
256 changes: 256 additions & 0 deletions tests/test_lf_controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
#include <string_view>
#include <tuple>

#include "utils/mutation.hpp"
using tests::utils::TemporaryMutate;

#include "utils/lf_controller.hpp"
using tests::utils::ExpectedLFControlFrom;
using tests::utils::MakeValidRandomControlFor;
using tests::utils::MakeValidRandomSensorFor;

#include "utils/robot_model.hpp"
using tests::utils::JointType;
using tests::utils::MakeAllModelDescriptionsFor;
using tests::utils::ModelDescription;

#include "utils/eigen_conversions.hpp"
using tests::utils::PushNewJointStateTo;

#include "linear_feedback_controller/lf_controller.hpp"
using linear_feedback_controller::LFController;

#include "gtest/gtest.h"

using namespace std::literals::string_view_literals;

namespace {

struct LFControllerTest : public ::testing::TestWithParam<ModelDescription> {};

TEST(LFControllerTest, Ctor) {
EXPECT_NO_THROW({ auto ctrl = LFController(); });
}

TEST(LFControllerTest, DISABLED_InitializeNullptr) {
auto ctrl = LFController();
EXPECT_ANY_THROW({ ctrl.initialize(nullptr); });
}

TEST(LFControllerTest, DISABLED_InitializeEmptyModel) {
auto ctrl = LFController();
EXPECT_ANY_THROW({
ctrl.initialize(
std::make_shared<linear_feedback_controller::RobotModelBuilder>());
});
}

TEST_P(LFControllerTest, Initialize) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
EXPECT_NO_THROW({ ctrl.initialize(model_ptr); });
}

TEST(LFControllerTest, DISABLED_ComputeControlNotInitialized) {
auto ctrl = LFController();
EXPECT_ANY_THROW({ auto _ = ctrl.compute_control({}, {}); });
}

TEST_P(LFControllerTest, DISABLED_ComputeControlNoInput) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
ctrl.initialize(model_ptr);

EXPECT_ANY_THROW({ auto _ = ctrl.compute_control({}, {}); });
}

TEST_P(LFControllerTest, DISABLED_ComputeControlUnknownJoints) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
ctrl.initialize(model_ptr);

const auto sensor = MakeValidRandomSensorFor(*model_ptr);
const auto control = MakeValidRandomControlFor(*model_ptr);

EXPECT_ANY_THROW({
auto wrong_sensor = sensor;
wrong_sensor.joint_state.name[0] = "this joint doesn't exist";
auto _ = ctrl.compute_control(wrong_sensor, control);
});
}

TEST_P(LFControllerTest, DISABLED_ComputeControlSizeMismatch) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
ctrl.initialize(model_ptr);

const auto sensor = MakeValidRandomSensorFor(*model_ptr);
const auto control = MakeValidRandomControlFor(*model_ptr);

EXPECT_ANY_THROW({
ArthurVal marked this conversation as resolved.
Show resolved Hide resolved
auto wrong_sensor = sensor;

// One more unknown joint inside sensor
PushNewJointStateTo(
wrong_sensor.joint_state,
{.name = "foo", .position = 0.0, .velocity = 0.0, .effort = 0.0});

auto _ = ctrl.compute_control(wrong_sensor, control);
});

EXPECT_ANY_THROW({
auto wrong_control = control;

// One more unknown joint inside control.initial_state
PushNewJointStateTo(
wrong_control.initial_state.joint_state,
{.name = "foo", .position = 0.0, .velocity = 0.0, .effort = 0.0});

auto _ = ctrl.compute_control(sensor, wrong_control);
});

EXPECT_ANY_THROW({
auto wrong_control = control;

// One more feed forward term
tests::utils::Grow(wrong_control.feedforward, 1);
wrong_control.feedforward.tail<1>()[0] = 0.0;

auto _ = ctrl.compute_control(sensor, wrong_control);
});

EXPECT_ANY_THROW({
auto wrong_control = control;

// One more row/col to feedback gain
tests::utils::Grow(wrong_control.feedback_gain, 1);

wrong_control.feedback_gain.bottomRows<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.cols());

wrong_control.feedback_gain.rightCols<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.rows());
Comment on lines +136 to +140
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
wrong_control.feedback_gain.bottomRows<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.cols());
wrong_control.feedback_gain.rightCols<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.rows());
wrong_control.feedback_gain.bottomRows<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.cols() + 1);
wrong_control.feedback_gain.rightCols<1>() =
::Eigen::VectorXd::Random(wrong_control.feedback_gain.rows());

Shouldn't at least one of those have +1? It seems that you are leaving value in bottom right corner unset. Even though it is very minor issue I think it would be nice to fix it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because of the Grow() above, the sizes match.
It's the opposite in fact, we are updating the bottom right element twice, but I'd say that it's not very important.

Also I guess Eigen would have report a size mismatch if it was the case (not sure ?).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, I am also not 100% sure, but I wouldn't assume it's all fine. When you compile in RelWithDebInfo or Release I think Eigen is stopping dynamic size checking. Maybe a good idea would to enforce that tests are build in Debug so that all possible asserts will be triggered. From my experience if Debug works all the rest will as well


auto _ = ctrl.compute_control(sensor, wrong_control);
});
}

/// Create a std::tuple<T&, string_view> with the ref expression as string
#define MakeRefOf(val) std::make_tuple(std::ref((val)), std::string_view{#val})

TEST_P(LFControllerTest, DISABLED_ComputeControlSpecialDouble) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
ctrl.initialize(model_ptr);

auto sensor = MakeValidRandomSensorFor(*model_ptr);
auto control = MakeValidRandomControlFor(*model_ptr);

// Test for special double values acceptance or not ?
for (const auto& [ref, str] : {
MakeRefOf(sensor.base_pose(0)),
MakeRefOf(sensor.base_pose(3)),
MakeRefOf(sensor.base_twist(4)),
MakeRefOf(sensor.joint_state.position(0)),
MakeRefOf(sensor.joint_state.velocity(0)),
MakeRefOf(control.feedforward(0)),
MakeRefOf(control.feedback_gain(0, 0)),
}) {
for (auto tmp_value : {
std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::signaling_NaN(),
}) {
const auto mutation = TemporaryMutate(ref, tmp_value);
EXPECT_ANY_THROW({ auto _ = ctrl.compute_control(sensor, control); })
<< str << " = " << tmp_value << " (was " << mutation.OldValue()
<< ")";
}
}
}

TEST_P(LFControllerTest, ComputeControl) {
const auto model_ptr = std::shared_ptr{MakeRobotModelBuilderFrom(GetParam())};
ASSERT_NE(model_ptr, nullptr);

auto ctrl = LFController();
ctrl.initialize(model_ptr);

const auto sensor = MakeValidRandomSensorFor(*model_ptr);
const auto control = MakeValidRandomControlFor(*model_ptr);
EXPECT_EQ(ExpectedLFControlFrom(*model_ptr, sensor, control),
ctrl.compute_control(sensor, control));
}

constexpr auto dummy_urdf =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<robot name=\"dummy\">"
" <link name=\"l0\"/>"
" "
" <joint name=\"l01\" type=\"revolute\">"
" <parent link=\"l0\"/>"
" <child link=\"l1\"/>"
" <origin xyz=\"0 0 1\" rpy=\"0 0 1\"/>"
" <axis xyz=\"0 0 1\"/>"
" <limit lower=\"0\" upper=\"3.14\" velocity=\"100\" effort=\"100\"/>"
" </joint>"
" "
" <link name=\"l1\"/>"
" "
" <joint name=\"l12\" type=\"revolute\">"
" <parent link=\"l1\"/>"
" <child link=\"l2\"/>"
" <origin xyz=\"0 1 0\" rpy=\"1 0 0\"/>"
" <axis xyz=\"0 1 0\"/>"
" <limit lower=\"-3.14\" upper=\"3.14\" velocity=\"100\" effort=\"10\"/>"
" </joint>"
" "
" <link name=\"l2\"/>"
"</robot>"sv;

INSTANTIATE_TEST_SUITE_P(
DummyUrdf, LFControllerTest,
::testing::ValuesIn(MakeAllModelDescriptionsFor(
dummy_urdf,
{
{
{.name = "l01"},
},
{
{.name = "l02", .type = JointType::Controlled},
},
{
{.name = "l01"},
{.name = "l12"},
},
})),
[](auto&& info) {
std::string str;
if (info.param.has_free_flyer) {
str.append("FreeFlyer_");
}

str.append(std::to_string(size(info.param.joint_list)));
str.append("_Joints");

for (const auto& [name, type] : info.param.joint_list) {
str.append("_");
str.append(name);
str.append("_");
str.append(ToString(type));
}

return str;
});

} // namespace
33 changes: 0 additions & 33 deletions tests/utils/array.hpp

This file was deleted.

Loading