12 #include <robottype.h>
13 #include <roboorte_robottype.h>
15 #define LINE_MIN_POINTS 7
16 #define LINE_ERROR_THRESHOLD 20
17 #define MAX_DISTANCE_POINT 300
21 typedef struct {float x,y;} Point;
23 typedef struct {Point a,b;} Line;
27 int perpendicular_regression(float &r, int &max_diff_idx, const int begin, const int end, vector<Point> &cartes)
29 int number_points = abs(end-begin) + 1;
31 if (number_points <= 0) return 1;
36 for (int i = begin; i <= end; i++) {
37 sum_x = sum_x + cartes[i].x;
38 sum_y = sum_y + cartes[i].y;
41 float med_x = sum_x / number_points;
42 float med_y = sum_y / number_points;
44 vector<Point> point_average(number_points);
50 for (int i = begin; i <= end; i++) {
51 tmp.x = cartes[i].x - med_x;
52 tmp.y = cartes[i].y - med_y;
53 point_average[j] = tmp;
60 for (int i = 0; i < number_points; i++) {
61 A = A + (point_average[i].x*point_average[i].x - point_average[i].y*point_average[i].y);
62 sum_xy = sum_xy + point_average[i].x * point_average[i].y;
65 if (sum_xy == 0) sum_xy = 1e-8;
69 // tan(q)^2 + A*tan(q) - 1 = 0 ( tan(q) sign as m ) -> quadratic equation
70 float m1 = (-A + sqrt(A*A + 4)) / 2;
71 float m2 = (-A - sqrt(A*A + 4)) / 2;
73 float b1 = med_y - m1*med_x;
74 float b2 = med_y - m2*med_x;
85 for (int i = begin; i < end; i++) {
86 // distance point from the line (A = m1, B = -1, C = b1)
87 dist = fabs( (cartes[i].x*m1 - cartes[i].y + b1) / sqrt(m1*m1 + 1) );
88 dist1 = fabs( (cartes[i].x*m2 - cartes[i].y + b2) / sqrt(m2*m2 + 1) );
111 void plot_line(int begin, int end, int maxdist, vector<Point> &cartes, vector<Line> &lines)
113 fprintf(gnuplot, "set grid\n");
114 fprintf(gnuplot, "set nokey\n");
115 fprintf(gnuplot, "set style line 1 lt 2 lc rgb \"red\" lw 3\n");
116 fprintf(gnuplot, "plot 'cartes1' with points ls 2, 'cartes2' with points ls 3");
118 fprintf(gnuplot, ", \"< echo \'%f %f \\n %f %f\'\" ls 4 with linespoints",cartes[begin].x, cartes[begin].y, cartes[end].x, cartes[end].y);
119 fprintf(gnuplot, ", \"< echo \'%f %f\'\" ls 1 pointsize 3 with points",cartes[maxdist].x, cartes[maxdist].y);
121 for (int i = 0; i < (int) lines.size(); i++) {
122 fprintf(gnuplot, ", \"< echo \'%f %f \\n %f %f\'\" ls 1 with linespoints",lines[i].a.x, lines[i].a.y, lines[i].b.x, lines[i].b.y);
125 fprintf(gnuplot, "\n");
130 // line recursive fitting
131 void line_fitting(int begin, int end, vector<Point> &cartes, vector<Line> &lines) {
132 int line_break_point;
133 //cout << "begin: " << begin << " end: " << end << endl << flush;
135 if ((end - begin) < LINE_MIN_POINTS) return;
138 if (perpendicular_regression(r, line_break_point, begin, end, cartes)) return; // r = 0
140 if (r < LINE_ERROR_THRESHOLD) {
144 line.a = cartes[begin];
145 line.b = cartes[end];
147 lines.push_back(line);
149 //cout << endl << "begin X: " << cartes[begin].x << " Y: " << cartes[begin].y << endl << flush;
150 //cout << "end X: " << cartes[end].x << " Y: " << cartes[end].y << endl << endl << flush;
153 // normal vector: n[n_x, -n_y]
155 float n_x = cartes[begin].y - cartes[end].y;
156 float n_y = cartes[begin].x - cartes[end].x;
160 float C = n_y*cartes[end].y - n_x*cartes[end].x;
162 int line_break_point = 0;
163 float dist, dist_max = 0;
165 for (int i = begin; i < end; i++) {
166 // distance point from the line
167 dist = fabs( (cartes[i].x*A + cartes[i].y*B + C) / sqrt(A*A + B*B));
169 if (dist > dist_max) {
171 line_break_point = i;
175 //plot_line(begin, end, line_break_point, cartes, lines);
177 if (dist_max > LINE_ERROR_THRESHOLD) {
178 line_fitting(begin, line_break_point, cartes, lines);
179 line_fitting(line_break_point, end, cartes, lines);
182 if (line_break_point == begin)
184 else if (line_break_point == end)
187 line_fitting(begin, line_break_point, cartes, lines);
188 line_fitting(line_break_point, end, cartes, lines);
190 } // end if (r <= LINE_ERROR_THRESHOLD)
195 // polar to cartesian coordinates
196 void polar_to_cartes(const vector<int> &input_data, vector<Point> &cartes) {
202 for (int i = 0; i < (int) input_data.size()-1; i++) {
203 r = (input_data[i] <= 19) ? 0 : input_data[i];
206 fi = HOKUYO_INDEX_TO_RAD(i);
207 point.x = r * cos(fi);
208 point.y = r * sin(fi);
209 cartes.push_back(point);
214 // save vector to file
215 void file_save(const vector<Point> &data, string name) {
217 file_name = new char[name.length() + 1];
218 strcpy(file_name, name.c_str());
220 FILE *file = fopen(file_name,"w");
222 for (int i = 0; i < (int) data.size(); i++)
223 fprintf(file, "%f, %f\n", data[i].x, data[i].y);
229 float point_distance(Point a, Point b) {
230 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
233 void shape_detect(const vector<int> &input_data, vector<Line> &lines) {
234 // polar coordinates to cartesian coordinates
235 vector<Point> cartes;
236 polar_to_cartes(input_data, cartes);
238 int cartes_size = cartes.size();
241 while (start < cartes_size) {
244 while (point_distance(cartes[end-1], cartes[end]) < MAX_DISTANCE_POINT && end < cartes_size)
249 line_fitting(start, end, cartes, lines);
252 fprintf(gnuplot, "set grid\n");
253 fprintf(gnuplot, "set nokey\n");
254 fprintf(gnuplot, "set style line 1 lt 2 lc rgb \"red\" lw 3\n");
256 fprintf(gnuplot, "plot [-1000:+3000] [-3000:+3000]");
257 fprintf(gnuplot, "'-' with points ls 2"); // points
258 fprintf(gnuplot, ", '-' ls 1 with linespoints"); // lines
259 fprintf(gnuplot, "\n");
262 for (int i = 0; i < (int) cartes.size(); i++) {
263 fprintf(gnuplot, "%g %g\n",cartes[i].x, cartes[i].y);
265 fprintf(gnuplot, "e\n");
268 for (int i = 0; i < (int) lines.size(); i++) {
269 fprintf(gnuplot, "%f %f\n%f %f\n\n",
270 lines[i].a.x, lines[i].a.y, lines[i].b.x, lines[i].b.y);
272 fprintf(gnuplot, "e\n");
276 struct robottype_orte_data orte;
278 void rcv_hokuyo_scan_cb(const ORTERecvInfo *info, void *vinstance,
279 void *recvCallBackParam)
281 struct hokuyo_scan_type *instance = (struct hokuyo_scan_type *)vinstance;
282 static int count = 0;
284 switch (info->status) {
291 vector<int> input(HOKUYO_ARRAY_SIZE);
293 for(unsigned i = 0; i < HOKUYO_ARRAY_SIZE; i++)
294 input[i] = (int) instance->data[HOKUYO_ARRAY_SIZE-1-i];
297 shape_detect(input, output);
302 printf("Deadline\n");
307 int robot_init_orte()
311 rv = robottype_roboorte_init(&orte);
314 robottype_subscriber_hokuyo_scan_create(&orte, rcv_hokuyo_scan_cb, &orte);
319 int main(int argc, char** argv) {
322 cout << "Error: Invalid number of input parameters." << endl;
326 vector<int> input_data;
328 ifstream infile(argv[1], ios_base::in);
333 // number from input file
338 while (getline(infile, line, ',')) {
344 stringstream strStream(line);
346 input_data.push_back(number);
351 vector<Line> output_data;
354 shape_detect(input_data, output_data);
361 gnuplot = popen("gnuplot", "w");