00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <iostream>
00029 #include <string>
00030
00031 #include <ros/ros.h>
00032
00033 #include <datamatrix_detection/DatamatrixMsg.h>
00034
00035 #include <image_transport/image_transport.h>
00036 #include <cv_bridge/cv_bridge.h>
00037 #include <sensor_msgs/image_encodings.h>
00038
00039 #include <opencv2/imgproc/imgproc.hpp>
00040 #include <opencv2/highgui/highgui.hpp>
00041
00042 #include <boost/format.hpp>
00043 #include <boost/shared_ptr.hpp>
00044
00045 #include <cmath>
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 class GlobalPosition: public cv::Point2d
00078 {
00079 public:
00080
00081 GlobalPosition()
00082 {
00083 phi = 0;
00084 x = 0;
00085 y = 0;
00086 }
00087
00088 GlobalPosition(double x_,double y_,double phi_):
00089 Point_(x_,y_)
00090 {
00091 phi = phi_;
00092 }
00093
00094 GlobalPosition operator=(const cv::Point2d& p)
00095 {
00096 return GlobalPosition(p.x,p.y,0);
00097 }
00098
00099 typedef boost::shared_ptr<GlobalPosition> Ptr;
00100
00101 double phi;
00102 };
00103
00104
00105 GlobalPosition operator+(const GlobalPosition& p1,const GlobalPosition& p2)
00106 {
00107 cv::Point2d po = static_cast<cv::Point2d>(p1)+static_cast<cv::Point2d>(p2);
00108
00109 return GlobalPosition(po.x,po.y,p1.phi+p2.phi);
00110 }
00111
00112 GlobalPosition::Ptr operator+(const GlobalPosition::Ptr& p1,const GlobalPosition::Ptr& p2)
00113 {
00114 return boost::make_shared<GlobalPosition>(*p1 + *p2);
00115 }
00116
00117 GlobalPosition operator/(const GlobalPosition& p1, double i)
00118 {
00119 return GlobalPosition(p1.x / i,p1.y / i ,p1.phi / i);
00120 }
00121
00122 GlobalPosition::Ptr operator/(const GlobalPosition::Ptr& p1, double i)
00123 {
00124 return boost::make_shared<GlobalPosition>(*p1/i);
00125 }
00126
00127 GlobalPosition operator*(const GlobalPosition& p1, double i)
00128 {
00129 return GlobalPosition(p1.x * i,p1.y * i ,p1.phi * i);
00130 }
00131
00132 GlobalPosition::Ptr operator*(const GlobalPosition::Ptr& p1, double i)
00133 {
00134 return boost::make_shared<GlobalPosition>(*p1 * i);
00135 }
00136
00137 class DataMatrixPosition
00138 {
00139 ros::NodeHandle nh_;
00140 ros::Subscriber datamatrix_sub;
00141 ros::Subscriber camera_info_sub;
00142
00143
00144 image_transport::ImageTransport it_;
00145 image_transport::Subscriber image_sub_;
00146
00147
00148 std::list<cv_bridge::CvImagePtr> frame_list;
00149
00150 datamatrix_detection::DatamatrixMsg datamatrix_msg;
00151 sensor_msgs::CameraInfo cam_info;
00152
00153
00154 cv::Mat plant;
00155 cv::Mat plant_img;
00156 cv::Point image_center;
00157 double plant_width;
00158 double matrix_real_height;
00159 double focal_length;
00160
00161 std::vector<double> distance;
00162 std::vector<double> alpha;
00163 std::vector<cv::Point2d> matrix_coordinates;
00164
00165
00166 typedef std::list<std::pair<double,GlobalPosition::Ptr> > DataList;
00167
00168 std::vector<GlobalPosition::Ptr> my_positions;
00169 DataList position_data;
00170
00171 public:
00172 DataMatrixPosition(const std::string& path, const double& mat_height, const double width)
00173 :it_(nh_)
00174 {
00175
00176 plant = cv::imread(path, CV_LOAD_IMAGE_COLOR);
00177 matrix_real_height = mat_height;
00178 plant_width = width;
00179
00180 SetupMessaging();
00181
00182 }
00183
00184 void SetupMessaging()
00185 {
00186
00187 image_sub_ = it_.subscribe("usb_cam_reader/image_rect_color", 1,
00188 &DataMatrixPosition::imageCallback, this);
00189
00190 camera_info_sub = nh_.subscribe("usb_cam_reader/camera_info", 1, &DataMatrixPosition::CameraInfoCallback, this);
00191 datamatrix_sub = nh_.subscribe("datamatrix_detection/datamatrix_msg", 1,&DataMatrixPosition::DataMatrixReceiveCallback, this);
00192 }
00193
00194 void CameraInfoCallback(const sensor_msgs::CameraInfo& cam_info_msg)
00195 {
00196
00197 cam_info = cam_info_msg;
00198 std::cout << cam_info_msg << std::endl;
00199
00200
00201 image_center.x = cam_info.width/2;
00202 image_center.y = cam_info.height/2;
00203 focal_length = (cam_info.P[0] + cam_info.P[5])/2;
00204
00205
00206 camera_info_sub.shutdown();
00207 }
00208
00209 void imageCallback(const sensor_msgs::ImageConstPtr& msg)
00210 {
00211 cv_bridge::CvImagePtr cv_ptr;
00212 try
00213 {
00214 cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
00215 }
00216 catch (cv_bridge::Exception& e)
00217 {
00218 ROS_ERROR("cv_bridge exception: %s", e.what());
00219 return;
00220 }
00221
00222
00223
00224
00225
00226 frame_list.push_back(cv_ptr);
00227
00228 if (frame_list.size() > 200 ) frame_list.pop_front();
00229
00230 }
00231
00232 void DataMatrixReceiveCallback(const datamatrix_detection::DatamatrixMsg& msg_data)
00233 {
00234 datamatrix_msg = msg_data;
00235 static int i = 0;
00236 for ( std::list<cv_bridge::CvImagePtr>::iterator it = frame_list.begin() ; it != frame_list.end(); it++)
00237 {
00238 cv_bridge::CvImagePtr img_ptr = *it;
00239 if (datamatrix_msg.header.stamp == img_ptr->header.stamp)
00240 {
00241 GetMatrixData();
00242 ImageDrawing(img_ptr->image);
00243 GetGlobalPositioning();
00244 GlobalPositioningView();
00245
00246
00247 cv::imshow("Imagem1",img_ptr->image);
00248 cv::imshow("Planta",plant_img);
00249 cv::waitKey(3);
00250 frame_list.erase(frame_list.begin(),it);
00251 distance.clear();
00252 alpha.clear();
00253 matrix_coordinates.clear();
00254
00255 datamatrix_msg.decoded_matrices.clear();
00256 break;
00257 }
00258 }
00259 }
00260
00261 void GetMatrixData()
00262 {
00263
00264 for (auto it = datamatrix_msg.decoded_matrices.begin(); it!=datamatrix_msg.decoded_matrices.end();)
00265 {
00266
00267 if ( it->code.size() % 2 == 0 )
00268 {
00269 std::string string_x = it->code.substr(0, it->code.size()/2);
00270 std::string string_y = it->code.substr(it->code.size()/2);
00271
00272 cv::Point matrix_coord(atoi(string_x.c_str()), atoi(string_y.c_str()) - 50 );
00273 matrix_coordinates.push_back(matrix_coord);
00274
00275 GetMatrixGeometry(it);
00276 GetMatrixDistance(it);
00277 GetMatrixAngle(it);
00278
00279
00280 it++;
00281 }
00282 else
00283 {
00284 it = datamatrix_msg.decoded_matrices.erase(it);
00285
00286 }
00287 }
00288 }
00289
00290 void GetMatrixGeometry(std::vector<datamatrix_detection::DatamatrixData>::iterator it)
00291 {
00292 it->matrix_center.x = (it->right.x + it->top.x)/2;
00293 it->matrix_center.y = (it->right.y + it->top.y)/2;
00294 it->matrix_center.z = 0;
00295
00296 cv::Point bottom_mean_point;
00297 bottom_mean_point.x = (it->right.x + it->bottom.x)/2;
00298 bottom_mean_point.y = (it->right.y + it->bottom.y)/2;
00299
00300 cv::Point left_mean_point;
00301 left_mean_point.x = (it->top.x + it->bottom.x)/2;
00302 left_mean_point.y = (it->top.y + it->bottom.y)/2;
00303
00304
00305 it->matrix_height = sqrt((bottom_mean_point.x - it->matrix_center.x)*(bottom_mean_point.x - it->matrix_center.x) + (bottom_mean_point.y - it->matrix_center.y)*(bottom_mean_point.y - it->matrix_center.y)) * 2;
00306
00307
00308 it->matrix_width = sqrt((left_mean_point.x - it->matrix_center.x)*(left_mean_point.x - it->matrix_center.x) + (left_mean_point.y - it->matrix_center.y)*(left_mean_point.y - it->matrix_center.y)) * 2;
00309 }
00310
00311 void GetMatrixDistance(std::vector<datamatrix_detection::DatamatrixData>::iterator it)
00312 {
00313
00314 if ( cam_info.P[0] != 0 )
00315 distance.push_back(matrix_real_height * focal_length/it->matrix_height);
00316 }
00317
00318 void GetMatrixAngle(std::vector<datamatrix_detection::DatamatrixData>::iterator it)
00319 {
00320
00321 if ( cam_info.P[0] != 0)
00322 {
00323 double center_dist_pix = image_center.x - it->matrix_center.x;
00324 alpha.push_back(( center_dist_pix/focal_length) * 180/M_PI);
00325 }
00326 }
00327
00328 void ImageDrawing(cv::Mat& cv_img)
00329 {
00330 for ( uint i = 0 ; i < datamatrix_msg.decoded_matrices.size(); i++)
00331 {
00332
00333 cv::circle(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].left.x, datamatrix_msg.decoded_matrices[i].left.y), 10, CV_RGB(255,0,0));
00334 cv::circle(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].right.x, datamatrix_msg.decoded_matrices[i].right.y), 10, CV_RGB(255,0,0));
00335 cv::circle(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].top.x, datamatrix_msg.decoded_matrices[i].top.y), 10, CV_RGB(255,0,0));
00336 cv::circle(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].bottom.x, datamatrix_msg.decoded_matrices[i].bottom.y), 10, CV_RGB(255,0,0));
00337 cv::circle(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].matrix_center.x, datamatrix_msg.decoded_matrices[i].matrix_center.y), 10, CV_RGB(255,0,0));
00338
00339 cv::Point top_right;
00340
00341
00342 double left_angle;
00343 double top_left_distance = sqrt((datamatrix_msg.decoded_matrices[i].top.x - datamatrix_msg.decoded_matrices[i].left.x)*(datamatrix_msg.decoded_matrices[i].top.x - datamatrix_msg.decoded_matrices[i].left.x) + (datamatrix_msg.decoded_matrices[i].top.y - datamatrix_msg.decoded_matrices[i].left.y)*(datamatrix_msg.decoded_matrices[i].top.y - datamatrix_msg.decoded_matrices[i].left.y));
00344
00345
00346 left_angle = atan2(datamatrix_msg.decoded_matrices[i].top.y - datamatrix_msg.decoded_matrices[i].left.y, datamatrix_msg.decoded_matrices[i].top.x - datamatrix_msg.decoded_matrices[i].left.x);
00347
00348
00349
00350 top_right.x = datamatrix_msg.decoded_matrices[i].right.x + round(datamatrix_msg.decoded_matrices[i].matrix_height*cos(left_angle));
00351 top_right.y = datamatrix_msg.decoded_matrices[i].right.y + round(datamatrix_msg.decoded_matrices[i].matrix_height*sin(left_angle));
00352
00353 cv::circle(cv_img, image_center, 10, CV_RGB(0,255,0));
00354 cv::circle(cv_img, top_right, 10, CV_RGB(0,255,0));
00355
00356
00357 if ( datamatrix_msg.decoded_matrices[i].top.y > datamatrix_msg.decoded_matrices[i].right.y && top_left_distance > 30)
00358 {
00359 cv::line(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].top.x, datamatrix_msg.decoded_matrices[i].top.y), cv::Point (datamatrix_msg.decoded_matrices[i].left.x, datamatrix_msg.decoded_matrices[i].left.y), cv::Scalar(0,255,0));
00360 cv::line(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].left.x, datamatrix_msg.decoded_matrices[i].left.y), cv::Point (datamatrix_msg.decoded_matrices[i].right.x, datamatrix_msg.decoded_matrices[i].right.y), cv::Scalar(0,255,0));
00361 }else{
00362 cv::line(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].top.x, datamatrix_msg.decoded_matrices[i].top.y), cv::Point (datamatrix_msg.decoded_matrices[i].bottom.x, datamatrix_msg.decoded_matrices[i].bottom.y), cv::Scalar(0,255,0));
00363 cv::line(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].bottom.x, datamatrix_msg.decoded_matrices[i].bottom.y), cv::Point (datamatrix_msg.decoded_matrices[i].right.x, datamatrix_msg.decoded_matrices[i].right.y), cv::Scalar(0,255,0));
00364 }
00365 cv::line(cv_img, cv::Point (datamatrix_msg.decoded_matrices[i].right.x, datamatrix_msg.decoded_matrices[i].right.y), top_right, cv::Scalar(0,255,0));
00366 cv::line(cv_img, top_right, cv::Point (datamatrix_msg.decoded_matrices[i].top.x, datamatrix_msg.decoded_matrices[i].top.y), cv::Scalar(0,255,0));
00367 cv::line(cv_img, cv::Point (1,cv_img.rows/2), cv::Point (cv_img.cols,cv_img.rows/2), cv::Scalar(255,0,0));
00368
00369
00370 std::string leitura = "Leitura: " + datamatrix_msg.decoded_matrices[i].code;
00371 cv::putText(cv_img, leitura, cv::Point (datamatrix_msg.decoded_matrices[i].top.x, datamatrix_msg.decoded_matrices[i].top.y - 15), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0,255,0), 2, 8);
00372
00373
00374 boost::format dist_str("Distancia: %1$.3f [m]");
00375 dist_str % distance[i];
00376 cv::putText(cv_img, dist_str.str(), cv::Point (datamatrix_msg.decoded_matrices[i].right.x + 15, datamatrix_msg.decoded_matrices[i].right.y), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0,255,0), 2, 8);
00377
00378
00379 boost::format ang_str("Angulo: %1$.3f [deg]");
00380 ang_str % alpha[i];
00381 cv::putText(cv_img, ang_str.str(), cv::Point (datamatrix_msg.decoded_matrices[i].bottom.x, datamatrix_msg.decoded_matrices[i].bottom.y + 20), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0,255,0), 2, 8);
00382 }
00383 }
00384
00385
00386 void GetGlobalPositioning()
00387 {
00388 if ( datamatrix_msg.decoded_matrices.size() >= 2 )
00389 {
00390
00391 GlobalPosition::Ptr my_estimated_position_ptr = EstimatePosition();
00392
00393
00394 static ros::Time prev_time;
00395 if ( prev_time.sec != 0 && my_estimated_position_ptr->x >= 0)
00396 position_data.push_front(std::make_pair((datamatrix_msg.header.stamp - prev_time).toSec(), my_estimated_position_ptr));
00397 if ( position_data.size() > 10 )
00398 position_data.pop_back();
00399 prev_time = datamatrix_msg.header.stamp;
00400
00401
00402
00403
00404 GlobalPosition::Ptr my_position_ptr = EMAPosition(position_data);
00405
00406
00407
00408
00409
00410 my_positions.push_back(my_position_ptr);
00411
00412 }else{
00413
00414 }
00415 }
00416
00417 void GlobalPositioningView()
00418 {
00419 plant_img = plant.clone();
00420
00421 double plant_cm_pix_ratio = plant_img.cols/plant_width;
00422
00423 if ( my_positions.size() > 0 )
00424 {
00425 GlobalPosition::Ptr my_position = my_positions.back();
00426 cv::circle(plant_img, cv::Point( plant_img.cols - (my_position->x * plant_cm_pix_ratio), my_position->y * plant_cm_pix_ratio), 3, CV_RGB(255,0,0));
00427 plant = plant_img.clone();
00428
00429 int arrow_size = 500;
00430 cv::Point arrow_end(plant_img.cols - (my_position->x + arrow_size * cos(my_position->phi)) * plant_cm_pix_ratio, (my_position->y + arrow_size * sin(my_position->phi)) * plant_cm_pix_ratio);
00431 cv::line(plant_img, cv::Point( plant_img.cols - (my_position->x * plant_cm_pix_ratio), my_position->y * plant_cm_pix_ratio), arrow_end, cv::Scalar(0,255,0), 3, CV_AA);
00432 }
00433
00434 for ( uint i = 0 ; i < datamatrix_msg.decoded_matrices.size(); i++)
00435 {
00436
00437 cv::Point matrix_pos(plant_img.cols - (matrix_coordinates[i].x * plant_cm_pix_ratio), matrix_coordinates[i].y * plant_cm_pix_ratio);
00438 cv::circle(plant_img, matrix_pos, distance[i] * 100 * plant_cm_pix_ratio, CV_RGB(255,0,0));
00439 cv::circle(plant_img, matrix_pos, 5, CV_RGB(255,0,0));
00440
00441 }
00442
00443
00444
00445 }
00446
00447 GlobalPosition::Ptr meanPosition(const DataList& data)
00448 {
00449 GlobalPosition::Ptr mean_pos(new GlobalPosition);
00450
00451 for(auto it = data.begin();it!=data.end();it++)
00452 mean_pos = mean_pos + it->second;
00453
00454 return mean_pos / data.size();
00455 }
00456
00457 GlobalPosition::Ptr EMAPosition(const DataList& data)
00458 {
00459
00460
00461 double denominator, alpha = 0.2;
00462 GlobalPosition::Ptr ema_pos (new GlobalPosition);
00463 int i = 0;
00464 for ( auto it = data.begin();it != data.end();it++)
00465 {
00466 double mult = pow((1-alpha),i++);
00467 ema_pos = ema_pos + it->second * mult;
00468 denominator = denominator + mult;
00469 }
00470
00471
00472
00473
00474 return ema_pos / denominator;
00475 }
00476
00477 GlobalPosition::Ptr WMAPosition(const DataList& data)
00478 {
00479 GlobalPosition::Ptr wma_pos (new GlobalPosition);
00480 double denominator;
00481 for ( auto it = data.begin();it != data.end();it++)
00482 {
00483 wma_pos = wma_pos + it->second * it->first;
00484 denominator = denominator + it->first;
00485 }
00486
00487 return wma_pos / denominator;
00488 }
00489
00490 GlobalPosition::Ptr EstimatePosition()
00491 {
00492
00493 std::vector<GlobalPosition::Ptr> my_intermediate_positions;
00494 GlobalPosition::Ptr sum(new GlobalPosition);
00495 for ( uint j = 0; j < datamatrix_msg.decoded_matrices.size() - 1; j++)
00496 {
00497 for ( uint k = j + 1; k < datamatrix_msg.decoded_matrices.size(); k++ )
00498 {
00499 GlobalPosition::Ptr my_intermediate_position_ptr = CalculateCircleIntersection( j, k );
00500 if (!std::isnan(my_intermediate_position_ptr->x) && !std::isnan(my_intermediate_position_ptr->y) && !std::isnan(my_intermediate_position_ptr->phi))
00501 {
00502 my_intermediate_positions.push_back(my_intermediate_position_ptr);
00503 sum = sum + my_intermediate_position_ptr;
00504 }
00505 }
00506 }
00507
00508 return sum / my_intermediate_positions.size();
00509 }
00510
00511
00512 GlobalPosition::Ptr CalculateCircleIntersection( uint first, uint second)
00513 {
00514
00515 double a, dx, dy, d, h, rx, ry;
00516 double x2, y2;
00517
00518
00519 double x0 = matrix_coordinates[first].x;
00520 double y0 = matrix_coordinates[first].y;
00521 double r0 = distance[first]*100;
00522
00523 double x1 = matrix_coordinates[second].x;
00524 double y1 = matrix_coordinates[second].y;
00525 double r1 = distance[second]*100;
00526
00527
00528
00529
00530 dx = x1 - x0;
00531 dy = y1 - y0;
00532
00533
00534
00535 d = hypot(dx,dy);
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
00556
00557
00558 x2 = x0 + (dx * a/d);
00559 y2 = y0 + (dy * a/d);
00560
00561
00562
00563
00564 h = sqrt((r0*r0) - (a*a));
00565
00566
00567
00568
00569 rx = -dy * (h/d);
00570 ry = dx * (h/d);
00571
00572
00573
00574 cv::Point2d int_point1(x2 + rx, y2 + ry);
00575 cv::Point2d int_point2(x2 - rx, y2 - ry);
00576
00577
00578
00579
00580
00581
00582
00583 cv::Point vetor_i1_m1 = matrix_coordinates[first] - int_point1;
00584 cv::Point vetor_i1_m2 = matrix_coordinates[second] - int_point1;
00585 int angle_direction_i1 = vetor_i1_m1.cross(vetor_i1_m2)/abs(vetor_i1_m1.cross(vetor_i1_m2));
00586
00587
00588
00589 cv::Point vetor_i2_m1 = matrix_coordinates[first] - int_point2;
00590 cv::Point vetor_i2_m2 = matrix_coordinates[second] - int_point2;
00591 int angle_direction_i2 = vetor_i2_m1.cross(vetor_i2_m2)/abs(vetor_i2_m1.cross(vetor_i2_m2));
00592
00593
00594
00595 int real_angle_direction = (alpha[second] - alpha[first])/(abs(alpha[second] - alpha[first]));
00596
00597
00598
00599 GlobalPosition::Ptr my_position_ptr(new GlobalPosition);
00600 if ( real_angle_direction / angle_direction_i1 == 1 )
00601 {
00602 my_position_ptr->x = int_point1.x;
00603 my_position_ptr->y = int_point1.y;
00604 }else if ( real_angle_direction / angle_direction_i2 == 1 )
00605 {
00606 my_position_ptr->x = int_point2.x;
00607 my_position_ptr->y = int_point2.y;
00608 }
00609
00610
00611
00612 double dx_ = matrix_coordinates[first].x - my_position_ptr->x;
00613 double dy_ = matrix_coordinates[first].y - my_position_ptr->y;
00614
00615 double int_mat1_angle = atan2( dy_,dx_ );
00616
00617 my_position_ptr->phi = int_mat1_angle - (alpha[first] * M_PI/180 );
00618
00619
00620 return my_position_ptr;
00621
00622
00623
00624 }
00625
00626
00627 };
00628
00629 int main(int argc, char** argv)
00630 {
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 ros::init(argc, argv, "datamatrix_calculations");
00674 ros::NodeHandle nh("~");
00675
00676 std::string path;
00677 nh.param<std::string>("plant_path",path,"");
00678
00679 double real_height;
00680 nh.param<double>("matrix_height",real_height,0);
00681
00682 double plant_width;
00683 nh.param<double>("plant_width",plant_width,0);
00684
00685 DataMatrixPosition datamatrix_pos(path, real_height, plant_width);
00686 ros::spin();
00687 return 0;
00688 }