45 #include <geometry_msgs/Pose.h> 46 #include <geometry_msgs/Twist.h> 47 #include <geometry_msgs/PoseArray.h> 50 #include <image_transport/image_transport.h> 53 #include <visp3/core/vpConfig.h> 54 #include <visp3/core/vpExponentialMap.h> 55 #include <visp3/core/vpImageConvert.h> 56 #include <visp3/core/vpMomentAreaNormalized.h> 57 #include <visp3/core/vpMomentBasic.h> 58 #include <visp3/core/vpMomentCentered.h> 59 #include <visp3/core/vpMomentDatabase.h> 60 #include <visp3/core/vpMomentGravityCenter.h> 61 #include <visp3/core/vpMomentGravityCenterNormalized.h> 62 #include <visp3/core/vpMomentObject.h> 63 #include <visp3/core/vpPixelMeterConversion.h> 64 #include <visp3/core/vpPoint.h> 65 #include <visp3/core/vpTime.h> 66 #include <visp3/detection/vpDetectorAprilTag.h> 67 #include <visp3/gui/vpDisplayX.h> 68 #include <visp3/visual_features/vpFeatureBuilder.h> 69 #include <visp3/visual_features/vpFeatureMomentAreaNormalized.h> 70 #include <visp3/visual_features/vpFeatureMomentGravityCenterNormalized.h> 71 #include <visp3/visual_features/vpFeatureVanishingPoint.h> 72 #include <visp3/vs/vpServo.h> 73 #include <visp3/vs/vpServoDisplay.h> 78 #if VISP_VERSION_INT > VP_VERSION_INT(3,2,0) // ViSP >= 3.0.0 88 ROS_WARN(
"No tag size parameter has been found, using default value : 0.14 meters.");
96 if (nh.
hasParam(
"/vs/distanceToTag")) {
97 nh.
getParam(
"/vs/distanceToTag", res);
100 ROS_WARN(
"No distance to tag parameter has been found, using default value : 1.5 meters.");
105 bool compareImagePoint(std::pair<size_t, vpImagePoint> p1, std::pair<size_t, vpImagePoint> p2)
107 return (p1.second.get_v() < p2.second.get_v());
114 virtual ~bebopVSNodelet();
118 void imageCallback(
const sensor_msgs::ImageConstPtr &msg);
126 bool bebop_has_been_setup;
128 vpDisplayX m_display;
129 bool m_display_setup;
130 vpImage<unsigned char> I;
139 vpDetectorAprilTag m_detector;
140 vpCameraParameters m_cam;
142 bool m_vec_ip_has_been_sorted;
143 std::vector<std::pair<size_t, vpImagePoint>> m_vec_ip_sorted;
145 vpVelocityTwistMatrix m_cVe;
155 vpMomentObject m_obj, m_obj_d;
156 vpMomentDatabase mdb, mdb_d;
158 vpMomentGravityCenter mg, mg_d;
159 vpMomentCentered mc, mc_d;
160 vpMomentAreaNormalized man, man_d;
161 vpMomentGravityCenterNormalized mgn, mgn_d;
163 vpFeatureMomentGravityCenterNormalized s_mgn, s_mgn_d;
164 vpFeatureMomentAreaNormalized s_man, s_man_d;
165 vpFeatureVanishingPoint s_vp, s_vp_d;
168 vpColVector velocityToPosition(vpColVector &vel_cmd,
double delta_t);
173 bebopVSNodelet::bebopVSNodelet()
174 : bebop_has_been_setup(false)
175 , m_display_setup(false)
176 , m_tagSize(getTagSize(m_nh))
177 , m_Z_d(getDistanceToTag(m_nh))
180 , m_detector(vpDetectorAprilTag::TAG_36h11)
181 , m_vec_ip_has_been_sorted(false)
182 , m_eJe(vpMatrix(6, 4, 0))
191 , s_mgn(mdb, A, B, C)
192 , s_mgn_d(mdb_d, A, B, C)
193 , s_man(mdb, A, B, C)
194 , s_man_d(mdb_d, A, B, C)
199 bebopVSNodelet::~bebopVSNodelet()
204 void bebopVSNodelet::onInit(){
207 std::stringstream params_str;
208 params_str <<
"TAG PARAMETERS (meters) : tagSize : " << m_tagSize
209 <<
" - distanceToTag : " << m_Z_d << std::endl;
215 m_pubTwist = m_nh.advertise<geometry_msgs::Twist>(
"cmd_moveby", 1000);
216 m_subImg = m_nh.subscribe(
"image_raw", 1000, &bebopVSNodelet::imageCallback,
this);
217 m_pubCam = m_nh.advertise<geometry_msgs::Twist>(
"camera_control", 1000);
218 NODELET_INFO(
"Publisher and subscriber set up. Waiting for image callbacks...");
221 void bebopVSNodelet::imageCallback(
const sensor_msgs::ImageConstPtr &msg)
223 if (!bebop_has_been_setup) {
224 geometry_msgs::Twist out_cam_ctrl;
225 out_cam_ctrl.linear.x = 0;
226 out_cam_ctrl.linear.y = 0;
227 out_cam_ctrl.linear.z = 0;
228 out_cam_ctrl.angular.x = 0;
229 out_cam_ctrl.angular.y = m_cameraTilt;
230 out_cam_ctrl.angular.z = m_cameraPan;
231 m_pubCam.publish(out_cam_ctrl);
233 bebop_has_been_setup =
true;
238 vpImageConvert::convert(frame, I);
240 if (!m_display_setup) {
241 m_display.init(I, 100, 100,
"DRONE VIEW");
242 m_display_setup =
true;
244 vpDisplay::display(I);
246 std::vector<vpHomogeneousMatrix> cMo_vec;
247 m_detector.detect(I, m_tagSize, m_cam, cMo_vec);
249 geometry_msgs::Twist out_cmd_pos;
251 if (m_detector.getNbObjects() == 1) {
253 std::vector<vpImagePoint> vec_ip = m_detector.getPolygon(0);
254 std::vector<vpPoint> vec_P;
255 for (
size_t i = 0; i < vec_ip.size(); i++) {
257 vpPixelMeterConversion::convertPoint(m_cam, vec_ip[i], x, y);
265 m_obj.setType(vpMomentObject::DENSE_POLYGON);
266 m_obj.fromVector(vec_P);
272 mdb.updateAll(m_obj);
280 s_mgn.update(A, B, C);
281 s_mgn.compute_interaction();
282 s_man.update(A, B, C);
283 s_man.compute_interaction();
288 if (!m_vec_ip_has_been_sorted) {
289 for (
size_t i = 0; i < vec_ip.size(); i++) {
291 std::pair<size_t, vpImagePoint> index_pair
292 = std::pair<size_t, vpImagePoint>(i, vec_ip[i]);
293 m_vec_ip_sorted.push_back(index_pair);
297 std::sort(m_vec_ip_sorted.begin(), m_vec_ip_sorted.end(), compareImagePoint);
299 m_vec_ip_has_been_sorted =
true;
303 vpFeatureBuilder::create(s_vp,
305 vec_ip[m_vec_ip_sorted[0].first],
306 vec_ip[m_vec_ip_sorted[1].first],
307 vec_ip[m_vec_ip_sorted[2].first],
308 vec_ip[m_vec_ip_sorted[3].first],
309 vpFeatureVanishingPoint::selectAtanOneOverRho());
311 m_task.set_cVe(m_cVe);
312 m_task.set_eJe(m_eJe);
315 vpColVector ve = m_task.computeControlLaw();
316 std::stringstream ve_str;
317 ve_str <<
"ve: " << ve.t() << std::endl;
321 vpColVector cmd_pos = velocityToPosition(ve, 1.0);
325 out_cmd_pos.linear.x = cmd_pos[0];
326 out_cmd_pos.linear.y = cmd_pos[1];
327 out_cmd_pos.linear.z = cmd_pos[2];
328 out_cmd_pos.angular.x = 0;
329 out_cmd_pos.angular.y = 0;
330 out_cmd_pos.angular.z = cmd_pos[3];
331 m_pubTwist.publish(out_cmd_pos);
333 for (
size_t i = 0; i < 4; i++) {
334 vpDisplay::displayCross(I, vec_ip[i], 15, vpColor::red, 1);
335 std::stringstream ss;
337 vpDisplay::displayText(I, vec_ip[i] + vpImagePoint(15, 15), ss.str(), vpColor::green);
341 vpDisplay::displayPolygon(I,
345 vpDisplay::displayCross(I,
346 m_detector.getCog(0),
350 vpDisplay::displayLine(I,
352 static_cast<int>(m_cam.get_u0()),
353 static_cast<int>(I.getHeight()) - 1,
354 static_cast<int>(m_cam.get_u0()),
357 vpDisplay::displayLine(I,
358 static_cast<int>(m_cam.get_v0()),
360 static_cast<int>(m_cam.get_v0()),
361 static_cast<int>(I.getWidth()) - 1,
366 vpDisplay::displayLine(I,
367 vec_ip[m_vec_ip_sorted[0].first],
368 vec_ip[m_vec_ip_sorted[1].first],
372 vpDisplay::displayLine(I,
373 vec_ip[m_vec_ip_sorted[2].first],
374 vec_ip[m_vec_ip_sorted[3].first],
379 vpDisplay::displayText(I, 10, 10,
"Click to exit", vpColor::red);
384 std::stringstream sserr;
385 sserr <<
"Failed to detect an Apriltag, or detected multiple ones";
386 vpDisplay::displayText(I, 120, 20, sserr.str(), vpColor::red);
390 out_cmd_pos.linear.x = 0;
391 out_cmd_pos.linear.y = 0;
392 out_cmd_pos.linear.z = 0;
393 out_cmd_pos.angular.x = 0;
394 out_cmd_pos.angular.y = 0;
395 out_cmd_pos.angular.z = 0;
396 m_pubTwist.publish(out_cmd_pos);
400 void bebopVSNodelet::initVS()
404 m_detector.setAprilTagQuadDecimate(4.0);
405 m_detector.setAprilTagNbThreads(4);
406 m_detector.setDisplayTag(
true);
408 m_cam.initPersProjWithoutDistortion(531.9213063, 520.8495788, 429.133986, 240.9464457);
409 m_cam.printParameters();
412 vpAdaptiveGain lambda = vpAdaptiveGain(1.5, 0.7, 30);
413 m_task.setServo(vpServo::EYEINHAND_L_cVe_eJe);
414 m_task.setInteractionMatrixType(vpServo::CURRENT);
415 m_task.setLambda(lambda);
417 if (m_nh.hasParam(
"/vs/cameraTilt")) {
418 m_nh.getParam(
"/vs/cameraTilt", m_cameraTilt);
420 ROS_WARN(
"No camera tilt value found, using default value : -15 degrees.");
421 m_cameraTilt = -15.0;
424 if (m_nh.hasParam(
"/vs/cameraPan")) {
425 m_nh.getParam(
"/vs/cameraPan", m_cameraPan);
427 ROS_WARN(
"No camera pan value found, using default value : 0 degrees.");
431 std::stringstream camparams_str;
432 camparams_str <<
"CAMERA PARAMETERS (degrees) : camera Tilt : " << m_cameraTilt
433 <<
" - camera pan : " << m_cameraPan << std::endl;
436 vpRxyzVector c1_rxyz_c2(vpMath::rad(m_cameraTilt), vpMath::rad(m_cameraPan), 0);
438 vpRotationMatrix c1Rc2(c1_rxyz_c2);
439 vpHomogeneousMatrix c1Mc2(vpTranslationVector(), c1Rc2);
441 vpRotationMatrix c1Re{0, 1, 0, 0, 0, 1, 1, 0, 0};
442 vpTranslationVector c1te(0, 0, -0.09);
443 vpHomogeneousMatrix c1Me(c1te, c1Re);
445 vpHomogeneousMatrix c2Me = c1Mc2.inverse() * c1Me;
448 m_cVe = vpVelocityTwistMatrix(c2Me);
449 m_task.set_cVe(m_cVe);
457 double X[4] = {m_tagSize / 2., m_tagSize / 2., -m_tagSize / 2., -m_tagSize / 2.};
458 double Y[4] = {m_tagSize / 2., -m_tagSize / 2., -m_tagSize / 2., m_tagSize / 2.};
460 std::vector<vpPoint> vec_P, vec_P_d;
461 for (
int i = 0; i < 4; i++) {
462 vpPoint P_d(X[i], Y[i], 0);
463 vpHomogeneousMatrix cdMo(0, 0, m_Z_d, 0, 0, 0);
465 vec_P_d.push_back(P_d);
469 m_obj_d.setType(vpMomentObject::DENSE_POLYGON);
470 m_obj_d.fromVector(vec_P_d);
477 mdb_d.updateAll(m_obj_d);
481 if (m_obj_d.getType() == vpMomentObject::DISCRETE)
482 area = mb_d.get(2, 0) + mb_d.get(0, 2);
484 area = mb_d.get(0, 0);
486 man_d.setDesiredArea(area);
492 m_task.addFeature(s_mgn, s_mgn_d);
493 m_task.addFeature(s_man, s_man_d);
494 m_task.addFeature(s_vp, s_vp_d, vpFeatureVanishingPoint::selectAtanOneOverRho());
497 s_mgn_d.update(A, B, C);
498 s_mgn_d.compute_interaction();
500 s_man_d.update(A, B, C);
501 s_man_d.compute_interaction();
504 s_vp_d.setAtanOneOverRho(0);
510 vpColVector bebopVSNodelet::velocityToPosition(vpColVector &vel_cmd,
double delta_t)
513 if (vel_cmd.size() != 4) {
515 "Can't compute velocity : dimension of the velocity vector should be equal to 4.");
516 res << 0., 0., 0., 0.;
527 vpHomogeneousMatrix M = vpExponentialMap::direct(ve, delta_t);
529 double epsilon = (std::numeric_limits<double>::epsilon());
530 if (std::abs(M.getRotationMatrix().getThetaUVector()[0]) >= epsilon) {
531 ROS_ERROR(
"Can't compute velocity : rotation around X axis should be 0.");
532 res << 0., 0., 0., 0.;
535 if (std::abs(M.getRotationMatrix().getThetaUVector()[1]) >= epsilon) {
536 ROS_ERROR(
"Can't compute velocity : rotation around Y axis should be 0.");
537 res << 0., 0., 0., 0.;
541 float dThetaZ =
static_cast<float>(M.getRotationMatrix().getThetaUVector()[2]);
542 vpTranslationVector t = M.getTranslationVector();
544 res << t[0], t[1], t[2], dThetaZ;
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE const tfScalar & x() const
ros::NodeHandle & getNodeHandle() const
#define NODELET_INFO(...)
bool getParam(const std::string &key, std::string &s) const
bool hasParam(const std::string &key) const
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)