// I have a problem.
// The kid next door (lets call him Sheldon) saw me drink some of my dads beers.
// Seven to be exact... Voodoo Rangers. I threw the cans into his back yard and
// they are spread all over his yard.
// He threatened to tell my dad if I can't compute their location in 3d coordinate space...
// By just measuring their distance between the cans! I used a tape measure.
// I picked one beer can to be the home base. I measured the distance between a few
// cans but I could not get every measurement. Some of the measurements weren't too good.
// The cans are all close to the ground so it should be easy, right?
// I googled the google problem solver and I came up with this and it seems to work.
// But Sheldon looked at my computer screen and saw the SQRT function. He laughed and
// ran back to his house, saying "Jacobian of a square root hahaha you idiot".
// Now I'm afraid I did something wrong... Is there a way to fix it?
// I've included my program.
// My name is Max., thank you for your help.
#include <iostream>
#include <ceres/ceres.h>
#include <vector>
// A thing to hold the location of a beer can
struct Location {
double x;
double y;
double z;
};
// A thing to hold the canA to canB distance measurements
struct Measurement {
unsigned int canA; // the first can number
unsigned int canB; // the second can number
double distance; // the measured distance between canA and canB
// google says I can weight the measurements with the inverse of the variance.
//double variance; // the error in the distance measurement how do I use this?
};
// The magic problem solver calls this a bunch of times to "hone in"
// on the best answer...
// I think it works by taking a guess and then this returns how wrong it is.
struct ErrorFunctor {
ErrorFunctor(double measurement)
: measurement_(measurement) {}
template<typename T>
bool operator()(const T* const x1, const T* const y1, const T* const z1,
const T* const x2, const T* const y2, const T* const z2,
T* residual) const
{
// this sqrt is what Sheldon is laughing about...
residual[0] = measurement_ - sqrt((x1[0]-x2[0])*(x1[0]-x2[0]) + (y1[0]-y2[0])*(y1[0]-y2[0]) + (z1[0]-z2[0])*(z1[0]-z2[0]));
return true;
}
const double measurement_;
};
int main(int argc, char** argv)
{
google::InitGoogleLogging(argv[0]);
// A thing to hold all my distance measurements
std::vector<Measurement> distances = {
{0, 1, 10.03},
{0, 2, 14.13},
{1, 2, 10.01},
{0, 3, 10.06},
{1, 3, 14.10},
{2, 3, 9.95},
{0, 4, 4.99},
{1, 4, 11.25},
{2, 4, 11.23},
{3, 4, 5.02},
{0, 5, 11.20},
{1, 5, 11.27},
{2, 5, 4.97},
{3, 5, 5.05},
{0, 6, 19.95},
{2, 6, 14.14},
{4, 6, 15.05},
{3, 6, 9.95}
};
// A thing to hold all the beer can locations
std::vector<Location> locations(7);
// Initialize the x,y,z positions of the mostly known cans
locations[0] = { 0.0, 0.0, 1.0};
locations[1] = {10.0, 0.0, 1.0};
locations[2] = {10.0, 10.0, 1.0};
// Initialize the mostly unknown cans -- wild guesses!
locations[3] = {0.1, 0.2, 1.0}; // failure if you start with zeros??
locations[4] = {10, 5, 1.0};
locations[5] = {-2, 4, 1.0};
locations[6] = { 0.1, 25, 1.0};
// this is the magic problem solver
ceres::Problem problem;
// First I tell the magic problem solver where I think the cans might be
// Some locations I'm fairly sure about but others not at all.
// So I add constant parameter blocks (constraints) for the things I'm sure about.
problem.AddParameterBlock(&locations[0].x, 1);
problem.AddParameterBlock(&locations[0].y, 1);
problem.AddParameterBlock(&locations[0].z, 1);
problem.SetParameterBlockConstant(&locations[0].x);
problem.SetParameterBlockConstant(&locations[0].y);
problem.SetParameterBlockConstant(&locations[0].z);
problem.AddParameterBlock(&locations[1].x, 1);
problem.AddParameterBlock(&locations[1].y, 1);
problem.AddParameterBlock(&locations[1].z, 1);
problem.SetParameterBlockConstant(&locations[1].x);
// problem.SetParameterBlockConstant(&locations[1].y);
problem.SetParameterBlockConstant(&locations[1].z);
problem.AddParameterBlock(&locations[2].x, 1);
problem.AddParameterBlock(&locations[2].y, 1);
problem.AddParameterBlock(&locations[2].z, 1);
// problem.SetParameterBlockConstant(&locations[2].x);
problem.SetParameterBlockConstant(&locations[2].y);
problem.SetParameterBlockConstant(&locations[2].z);
// Add parameter blocks for the unknown cans
problem.AddParameterBlock(&locations[3].x, 1);
problem.AddParameterBlock(&locations[3].y, 1);
problem.AddParameterBlock(&locations[3].z, 1);
// problem.SetParameterBlockConstant(&locations[3].z);
problem.AddParameterBlock(&locations[4].x, 1);
problem.AddParameterBlock(&locations[4].y, 1);
problem.AddParameterBlock(&locations[4].z, 1);
// problem.SetParameterBlockConstant(&locations[4].z);
problem.AddParameterBlock(&locations[5].x, 1);
problem.AddParameterBlock(&locations[5].y, 1);
problem.AddParameterBlock(&locations[5].z, 1);
// problem.SetParameterBlockConstant(&locations[5].z);
problem.AddParameterBlock(&locations[6].x, 1);
problem.AddParameterBlock(&locations[6].y, 1);
problem.AddParameterBlock(&locations[6].z, 1);
// problem.SetParameterBlockConstant(&locations[6].z);
// This tells the magic problem solver about all my measurements.
for (const auto& measure : distances) {
unsigned int canA = measure.canA;
unsigned int canB = measure.canB;
double distAB = measure.distance;
problem.AddResidualBlock(
new ceres::AutoDiffCostFunction<ErrorFunctor, 1, 1, 1, 1, 1, 1, 1>(
new ErrorFunctor(distAB)),
nullptr,
&locations[canA].x, &locations[canA].y, &locations[canA].z,
&locations[canB].x, &locations[canB].y, &locations[canB].z
);
}
ceres::Solver::Options options;
options.max_num_iterations = 100;
//options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
// This is the where the magic happens!
ceres::Solve(options, &problem, &summary);
std::cout << summary.FullReport() << std::endl;
std::cout << "Estimated Beer Can Locations:" << std::endl;
for (unsigned int i = 0; i < locations.size(); ++i) {
std::cout << "Can " << i << ": (" << locations[i].x << ", " << locations[i].y << ", " << locations[i].z << ")" << std::endl;
}
return 0;
}