example showing how to do visual servoing of Parrot Bebop 2 drone.
WARNING: this program does no sensing or avoiding of obstacles, the drone WILL collide with any objects in the way! Make sure the drone has about 3-4 meters of free space around it before starting the program.
This program makes the drone detect and follow an AprilTag from the 36h11 family.
#include <iostream>
#include <visp3/core/vpConfig.h>
#include <visp3/core/vpMomentAreaNormalized.h>
#include <visp3/core/vpMomentBasic.h>
#include <visp3/core/vpMomentCentered.h>
#include <visp3/core/vpMomentDatabase.h>
#include <visp3/core/vpMomentGravityCenter.h>
#include <visp3/core/vpMomentGravityCenterNormalized.h>
#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPixelMeterConversion.h>
#include <visp3/core/vpPoint.h>
#include <visp3/core/vpTime.h>
#include <visp3/detection/vpDetectorAprilTag.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/gui/vpPlot.h>
#include <visp3/robot/vpRobotBebop2.h>
#include <visp3/visual_features/vpFeatureBuilder.h>
#include <visp3/visual_features/vpFeatureMomentAreaNormalized.h>
#include <visp3/visual_features/vpFeatureMomentGravityCenterNormalized.h>
#include <visp3/visual_features/vpFeatureVanishingPoint.h>
#include <visp3/vs/vpServo.h>
#include <visp3/vs/vpServoDisplay.h>
#ifdef VISP_HAVE_PUGIXML
#include <visp3/core/vpXmlParserCamera.h>
#endif
#if !defined(VISP_HAVE_ARSDK)
int main()
{
std::cout << "\nThis example requires Parrot ARSDK3 library. You should install it.\n" << std::endl;
return EXIT_SUCCESS;
}
#elif !defined(VISP_HAVE_FFMPEG)
int main()
{
std::cout << "\nThis example requires ffmpeg library. You should install it.\n" << std::endl;
return EXIT_SUCCESS;
}
#else
bool compareImagePoint(std::pair<size_t, vpImagePoint> p1, std::pair<size_t, vpImagePoint> p2)
{
return (p1.second.get_v() < p2.second.get_v());
};
int main(int argc, char **argv)
{
try {
std::string ip_address = "192.168.42.1";
std::string opt_cam_parameters;
bool opt_has_cam_parameters = false;
double tagSize = -1;
double opt_distance_to_tag = -1;
bool opt_has_distance_to_tag = false;
int stream_res = 0;
bool verbose = false;
if (argc >= 3 && std::string(argv[1]) == "--tag_size") {
tagSize = std::atof(argv[2]);
if (tagSize <= 0) {
std::cout << "Error : invalid tag size." << std::endl << "See " << argv[0] << " --help" << std::endl;
return 0;
}
for (int i = 3; i < argc; i++) {
if (std::string(argv[i]) == "--ip" && i + 1 < argc) {
ip_address = std::string(argv[i + 1]);
i++;
} else if (std::string(argv[i]) == "--distance_to_tag" && i + 1 < argc) {
opt_distance_to_tag = std::atof(argv[i + 1]);
if (opt_distance_to_tag <= 0) {
std::cout << "Error : invalid distance to tag." << std::endl << "See " << argv[0] << " --help" << std::endl;
return 0;
}
opt_has_distance_to_tag = true;
i++;
} else if (std::string(argv[i]) == "--intrinsic") {
#ifdef VISP_HAVE_PUGIXML
opt_cam_parameters = std::string(argv[i + 1]);
opt_has_cam_parameters = true;
i++;
#else
std::cout << "PUGIXML is required for custom camera parameters input." << std::endl;
return 0;
#endif
} else if (std::string(argv[i]) == "--hd_stream") {
stream_res = 1;
} else if (std::string(argv[i]) == "--verbose" || std::string(argv[i]) == "-v") {
verbose = true;
} else {
std::cout << "Error : unknown parameter " << argv[i] << std::endl
<< "See " << argv[0] << " --help" << std::endl;
return 0;
}
}
} else if (argc >= 2 && (std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h")) {
std::cout << "\nUsage:\n"
<< " " << argv[0]
<< " [--tag_size <size>] [--ip <drone ip>] [--distance_to_tag <distance>] [--intrinsic <xml file>] "
<< "[--hd_stream] [--verbose] [-v] [--help] [-h]\n"
<< std::endl
<< "Description:\n"
<< " --tag_size <size>\n"
<< " The size of the tag to detect in meters, required.\n\n"
<< " --ip <drone ip>\n"
<< " Ip address of the drone to which you want to connect (default : 192.168.42.1).\n\n"
<< " --distance_to_tag <distance>\n"
<< " The desired distance to the tag in meters (default: 1 meter).\n\n"
<< " --intrinsic <xml file>\n"
<< " XML file containing computed intrinsic camera parameters (default: empty).\n\n"
<< " --hd_stream\n"
<< " Enables HD 720p streaming instead of default 480p.\n"
<< " Allows to increase range and accuracy of the tag detection,\n"
<< " but increases latency and computation time.\n"
<< " Caution: camera calibration settings are different for the two resolutions.\n"
<< " Make sure that if you pass custom intrinsic camera parameters,\n"
<< " they were obtained with the correct resolution.\n\n"
<< " --verbose, -v\n"
<< " Enables verbose (drone information messages and velocity commands\n"
<< " are then displayed).\n\n"
<< " --help, -h\n"
<< " Print help message.\n"
<< std::endl;
return 0;
} else {
std::cout << "Error : tag size parameter required." << std::endl << "See " << argv[0] << " --help" << std::endl;
return 0;
}
std::cout
<< "\nWARNING: \n - This program does no sensing or avoiding of "
"obstacles, \n"
"the drone WILL collide with any objects in the way! Make sure "
"the \n"
"drone has approximately 3 meters of free space on all sides.\n"
" - The drone uses a downward-facing camera for horizontal speed estimation,\n make sure the drone flies "
"above a non-uniform flooring,\n or its movement will be inacurate and dangerous !\n"
<< std::endl;
verbose, true, ip_address);
true);
#if defined VISP_HAVE_X11
#elif defined VISP_HAVE_GTK
#elif defined VISP_HAVE_GDI
#elif defined VISP_HAVE_OPENCV
#endif
int orig_displayX = 100;
int orig_displayY = 100;
display.
init(I, orig_displayX, orig_displayY,
"DRONE VIEW");
vpPlot plotter(1, 700, 700, orig_displayX + static_cast<int>(I.
getWidth()) + 20, orig_displayY,
"Visual servoing tasks");
unsigned int iter = 0;
if (opt_has_cam_parameters) {
std::cout << "Cannot find parameters in XML file " << opt_cam_parameters << std::endl;
} else {
}
}
} else {
std::cout << "Setting default camera parameters ... " << std::endl;
} else {
}
}
eJe[0][0] = 1;
eJe[1][1] = 1;
eJe[2][2] = 1;
eJe[5][3] = 1;
double Z_d = (opt_has_distance_to_tag ? opt_distance_to_tag : 1.);
double X[4] = {tagSize / 2., tagSize / 2., -tagSize / 2., -tagSize / 2.};
double Y[4] = {tagSize / 2., -tagSize / 2., -tagSize / 2., tagSize / 2.};
std::vector<vpPoint> vec_P, vec_P_d;
for (int i = 0; i < 4; i++) {
vec_P_d.push_back(P_d);
}
double area = 0;
area = mb_d.
get(2, 0) + mb_d.
get(0, 2);
else
double A = 0.0;
double B = 0.0;
double C = 1.0 / Z_d;
bool runLoop = true;
bool vec_ip_has_been_sorted = false;
std::vector<std::pair<size_t, vpImagePoint> > vec_ip_sorted;
std::vector<vpHomogeneousMatrix> cMo_vec;
detector.
detect(I, tagSize, cam, cMo_vec);
{
std::stringstream ss;
ss << "Detection time: " << t << " ms";
}
std::vector<vpImagePoint> vec_ip = detector.
getPolygon(0);
vec_P.clear();
for (size_t i = 0; i < vec_ip.size(); i++) {
double x = 0, y = 0;
vec_P.push_back(P);
}
m_obj.fromVector(vec_P);
man.linkTo(mdb);
man.setDesiredArea(area);
man.compute();
s_mgn.update(A, B, C);
s_mgn.compute_interaction();
s_man.update(A, B, C);
s_man.compute_interaction();
if (!vec_ip_has_been_sorted) {
for (size_t i = 0; i < vec_ip.size(); i++) {
std::pair<size_t, vpImagePoint> index_pair = std::pair<size_t, vpImagePoint>(i, vec_ip[i]);
vec_ip_sorted.push_back(index_pair);
}
std::sort(vec_ip_sorted.begin(), vec_ip_sorted.end(), compareImagePoint);
vec_ip_has_been_sorted = true;
}
vec_ip[vec_ip_sorted[2].first], vec_ip[vec_ip_sorted[3].first],
if (verbose) {
std::cout <<
"ve: " << ve.
t() << std::endl;
}
for (size_t i = 0; i < 4; i++) {
std::stringstream ss;
ss << i;
}
3);
3);
3);
false);
false);
} else {
std::stringstream sserr;
sserr << "Failed to detect an Apriltag, or detected multiple ones";
}
runLoop = false;
}
std::stringstream sstime;
sstime << "Total time: " << totalTime << " ms";
iter++;
}
return EXIT_SUCCESS;
} else {
std::cout << "ERROR : failed to setup drone control." << std::endl;
return EXIT_FAILURE;
}
std::cout << "Caught an exception: " << e << std::endl;
return EXIT_FAILURE;
}
}
#endif // #elif !defined(VISP_HAVE_FFMPEG)