2025-02-18 22:15:27 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Photon Vision.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include <wpi/timestamp.h>
|
|
|
|
|
|
|
|
|
|
#include "photon/constrained_solvepnp/wrap/casadi_wrapper.h"
|
|
|
|
|
|
|
|
|
|
#define TAG_COUNT 6
|
|
|
|
|
#if TAG_COUNT < 1
|
|
|
|
|
#error TAG_COUNT cannot be less than 1!
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
using casadi_real = double;
|
|
|
|
|
|
|
|
|
|
void print_cost(casadi_real robot_x, casadi_real robot_y,
|
|
|
|
|
casadi_real robot_theta) {
|
|
|
|
|
casadi_real fx = 600;
|
|
|
|
|
casadi_real fy = 600;
|
|
|
|
|
casadi_real cx = 300;
|
|
|
|
|
casadi_real cy = 150;
|
|
|
|
|
|
|
|
|
|
constexpr int NUM_LANDMARKS = 4 * TAG_COUNT;
|
|
|
|
|
|
|
|
|
|
// Note that casadi is column major, apparently
|
|
|
|
|
Eigen::Matrix<casadi_real, 4, 4, Eigen::ColMajor> robot2camera;
|
|
|
|
|
// clang-format off
|
|
|
|
|
robot2camera <<
|
|
|
|
|
0, 0, 1, 0,
|
|
|
|
|
-1, 0, 0, 0,
|
|
|
|
|
0, -1, 0, 0,
|
|
|
|
|
0, 0, 0, 1;
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
Eigen::Matrix<casadi_real, NUM_LANDMARKS, 4, Eigen::ColMajor> field2points_;
|
|
|
|
|
// clang-format off
|
|
|
|
|
field2points_ <<
|
|
|
|
|
#if TAG_COUNT > 7
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 6
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 5
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 4
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 3
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 2
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 1
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
#endif
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 - 0.08255, 1,
|
|
|
|
|
2.5, 0 - 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 + 0.08255, 1,
|
|
|
|
|
2.5, 0 + 0.08255, 0.5 - 0.08255, 1;
|
|
|
|
|
// clang-format on
|
|
|
|
|
Eigen::Matrix<casadi_real, 4, NUM_LANDMARKS, Eigen::ColMajor> field2points =
|
|
|
|
|
field2points_.transpose();
|
|
|
|
|
|
|
|
|
|
Eigen::Matrix<casadi_real, NUM_LANDMARKS, 2, Eigen::ColMajor>
|
|
|
|
|
point_observations_;
|
|
|
|
|
// clang-format off
|
|
|
|
|
point_observations_ <<
|
|
|
|
|
#if TAG_COUNT > 7
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 6
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 5
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 4
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 3
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 2
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
#if TAG_COUNT > 1
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17,
|
|
|
|
|
#endif
|
|
|
|
|
333, -17,
|
|
|
|
|
333, -83,
|
|
|
|
|
267, -83,
|
|
|
|
|
267, -17;
|
|
|
|
|
// clang-format on
|
|
|
|
|
Eigen::Matrix<casadi_real, 2, NUM_LANDMARKS, Eigen::ColMajor>
|
|
|
|
|
point_observations = point_observations_.transpose();
|
|
|
|
|
|
|
|
|
|
Eigen::Vector3d x_guess;
|
|
|
|
|
x_guess << robot_x, robot_y, robot_theta;
|
|
|
|
|
|
Use normalized pixels in cPNP problem formulation (#1816)
## Description
instead of using camera calibration, the CasADi problem formulation now
expect the caller to provide "normalized pixel coordinates". This
reduces the number of floating point operations we need to perform (and
reduces total LOC by 6%). `casadi_wrapper.cpp` now converts from (u, v)
coordinates to normalized (x'', y'') coordinates with:
x'' = (u - c_x) / f_x
y'' = (u - c_y) / f_y
Which is the inverse of this (from [opencv
docs](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html), and
assuming no distortion):

In my testing, this is ~16% faster on my x86 laptop. Would love some rio
benchmarks.
## Meta
Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_
- [~] If this PR changes behavior or adds a feature, user documentation
is updated
- [~] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [~] If this PR touches configuration, this is backwards compatible
with settings back to v2024.3.1
- [~] If this PR addresses a bug, a regression test for it is added
2025-03-18 21:34:56 -07:00
|
|
|
for (int i = 0; i < 200; i++) {
|
2025-02-18 22:15:27 -08:00
|
|
|
auto start = wpi::Now();
|
|
|
|
|
auto x_out = constrained_solvepnp::do_optimization(
|
|
|
|
|
true, TAG_COUNT,
|
|
|
|
|
constrained_solvepnp::CameraCalibration{fx, fy, cx, cy}, robot2camera,
|
|
|
|
|
x_guess, field2points, point_observations, 0, 0);
|
|
|
|
|
auto end = wpi::Now();
|
|
|
|
|
|
Use normalized pixels in cPNP problem formulation (#1816)
## Description
instead of using camera calibration, the CasADi problem formulation now
expect the caller to provide "normalized pixel coordinates". This
reduces the number of floating point operations we need to perform (and
reduces total LOC by 6%). `casadi_wrapper.cpp` now converts from (u, v)
coordinates to normalized (x'', y'') coordinates with:
x'' = (u - c_x) / f_x
y'' = (u - c_y) / f_y
Which is the inverse of this (from [opencv
docs](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html), and
assuming no distortion):

In my testing, this is ~16% faster on my x86 laptop. Would love some rio
benchmarks.
## Meta
Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_
- [~] If this PR changes behavior or adds a feature, user documentation
is updated
- [~] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [~] If this PR touches configuration, this is backwards compatible
with settings back to v2024.3.1
- [~] If this PR addresses a bug, a regression test for it is added
2025-03-18 21:34:56 -07:00
|
|
|
std::cout << i << "," << static_cast<bool>(x_out) << "," << end - start
|
|
|
|
|
<< std::endl;
|
|
|
|
|
std::cout << "Solution:"
|
|
|
|
|
<< x_out.value_or(constrained_solvepnp::RobotStateMat::Identity())
|
|
|
|
|
<< std::endl;
|
|
|
|
|
// std::cout << "iter "
|
|
|
|
|
// << i
|
|
|
|
|
// // << "\nGuess:\n" << x_guess << "\n Optimized ->\n"
|
|
|
|
|
// // << std::endl <<
|
|
|
|
|
// // x_out.value_or(constrained_solvepnp::RobotStateMat::Zero())
|
|
|
|
|
// << " - Succeeded? " << static_cast<bool>(x_out) << " - In "
|
|
|
|
|
// << (end - start) << "uS" << std::endl;
|
2025-02-18 22:15:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CasadiWrapperTest, smoketest) { print_cost(0.1, 0.1, 0.0); }
|