2 * Copyright Droids Corporation (2009)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Revision : $Id: f16.h,v 1.6.4.3 2008-05-10 15:06:26 zer0 Exp $
29 #include <vect_base.h>
33 #define POS_ACCURACY 10.0 /* 1 cm accuracy max */
35 #define printf(args...) do {} while(0)
38 static int dprint = 0;
39 #define dprintf(args...) if (dprint) printf(args)
44 #define ANGLE_EPSILON 0.005
46 const point_t beacon0 = { 0, 1050 };
47 const point_t beacon1 = { 3000, 0 };
48 const point_t beacon2 = { 3000, 2100 };
50 static inline double abs_dbl(double x)
58 /* Fill the 2 circles pointer given as parameter, each of those cross
59 * both beacons b1 and b2. From any point of these circles (except b1
60 * and b2), we see b1 and b2 with the angle of a_rad (which must be
61 * positive). Return 0 on success.
64 * <------------------------->
67 * +----------------------------+
70 * / \ \ a___ | | d / | `.
85 * '`--......---' R (the robot)
88 int8_t angle_to_circles(circle_t *c1, circle_t *c2,
89 const point_t *b1, const point_t *b2,
96 /* reject too small angles */
97 if (a_rad <= 0.01 && a_rad >= -0.01)
100 /* get position of O */
101 O.x = (b1->x + b2->x) / 2;
102 O.y = (b1->y + b2->y) / 2;
104 /* get the length l */
109 /* distance from O to the center of the circle */
110 /* XXX div by 0 when pi */
111 d = l / (2 * tan(a_rad));
113 /* get the circle c1 */
119 c1->r = xy_norm(b1->x, b1->y, c1->x, c1->y);
122 /* get the circle c2 */
126 c2->r = xy_norm(b1->x, b1->y, c1->x, c1->y);
132 /* get the position of the robot from the angle of the 3 beacons */
133 int8_t angles_to_posxy(point_t *pos, double a01, double a12, double a20)
135 circle_t c01, c12, c20;
136 point_t dummy_pt, p1, p2, p3;
138 dprintf("a01 = %2.2f\n", a01);
139 dprintf("a12 = %2.2f\n", a12);
140 dprintf("a20 = %2.2f\n", a20);
142 if (angle_to_circles(&c01, NULL, &beacon0, &beacon1, a01))
144 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", c01.x, c01.y, c01.r);
146 if (angle_to_circles(&c12, NULL, &beacon1, &beacon2, a12))
148 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", c12.x, c12.y, c12.r);
150 if (angle_to_circles(&c20, NULL, &beacon2, &beacon0, a20))
152 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", c20.x, c20.y, c20.r);
154 if (circle_intersect(&c01, &c12, &p1, &dummy_pt) == 0)
156 if (circle_intersect(&c12, &c20, &p2, &dummy_pt) == 0)
158 if (circle_intersect(&c20, &c01, &dummy_pt, &p3) == 0)
161 dprintf("p1: x=%2.2f y=%2.2f\n", p1.x, p1.y);
162 dprintf("p2: x=%2.2f y=%2.2f\n", p2.x, p2.y);
163 dprintf("p3: x=%2.2f y=%2.2f\n", p3.x, p3.y);
165 /* if (xy_norm(p1.x, p1.y, p2.x, p2.y) > POS_ACCURACY || */
166 /* xy_norm(p2.x, p2.y, p3.x, p3.y) > POS_ACCURACY || */
167 /* xy_norm(p3.x, p3.y, p1.x, p1.y) > POS_ACCURACY) */
170 pos->x = (p1.x + p2.x + p3.x) / 3.0;
171 pos->y = (p1.y + p2.y + p3.y) / 3.0;
176 static inline int8_t is_pt_in_area(point_t pt)
178 if (pt.x < 0 || pt.y < 0)
180 if (pt.x > AREA_X || pt.y > AREA_Y)
185 /* intersect the circle formed by one distance info with the circle
186 * crossing the 2 beacons */
188 ad_to_posxy_one(point_t *pos,
189 const point_t *b0, const point_t *b1, /* beacon position */
190 const circle_t *cd, const circle_t *c01, /* circles to intersect */
191 double a01) /* seen angle of beacons */
193 double tmp_a01_p1, tmp_a01_p2;
195 uint8_t p1_ok=0, p2_ok=0;
197 if (circle_intersect(c01, cd, &p1, &p2) == 0)
200 dprintf("p1: x=%2.2f y=%2.2f\n", p1.x, p1.y);
201 dprintf("p2: x=%2.2f y=%2.2f\n", p2.x, p2.y);
203 dprintf("real a01: %2.2f\n", a01);
205 tmp_a01_p1 = atan2(b1->y-p1.y, b1->x-p1.x) -
206 atan2(b0->y-p1.y, b0->x-p1.x);
207 if (tmp_a01_p1 > M_PI)
208 tmp_a01_p1 -= 2*M_PI;
209 if (tmp_a01_p1 < -M_PI)
210 tmp_a01_p1 += 2*M_PI;
211 dprintf("a01-1: %2.2f\n", tmp_a01_p1);
213 tmp_a01_p2 = atan2(b1->y-p2.y, b1->x-p2.x) -
214 atan2(b0->y-p2.y, b0->x-p2.x);
215 if (tmp_a01_p2 > M_PI)
216 tmp_a01_p2 -= 2*M_PI;
217 if (tmp_a01_p2 < -M_PI)
218 tmp_a01_p2 += 2*M_PI;
219 dprintf("a01-2: %2.2f\n", tmp_a01_p2);
221 /* in some conditions, we already know the position of the
222 * robot at this step */
223 p1_ok = is_pt_in_area(p1) &&
224 abs_dbl(tmp_a01_p1 - a01) < ANGLE_EPSILON;
226 p2_ok = is_pt_in_area(p2) &&
227 abs_dbl(tmp_a01_p2 - a01) < ANGLE_EPSILON;
228 if (!p1_ok && p2_ok) {
232 if (p1_ok && !p2_ok) {
240 ad_to_posxy_algo(point_t *pos, int algo,
241 const point_t *b0, const point_t *b1, /* beacon position */
242 const circle_t *cd0, const circle_t *cd1, const circle_t *c01, /* circles to intersect */
243 double a01, /* seen angle of beacons */
244 double d0, double d1 /* distance to beacons */ )
249 /* take the closer beacon first */
252 if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
254 if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
259 if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
261 if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
268 if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
273 if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
283 /* get the position and angle of the robot from the angle of the 2
284 * beacons, and the distance of 2 beacons */
286 ad_to_posxya(point_t *pos, double *a, int algo,
287 const point_t *b0, const point_t *b1, /* beacon position */
288 double a0, double a1, /* seen angle of beacons */
289 double d0, double d1 /* distance to beacons */ )
291 circle_t cd0, cd1, c01;
294 dprintf("algo=%d a0=%2.2f a1=%2.2f d0=%2.2f d1=%2.2f\n",
295 algo, a0, a1, d0, d1);
297 /* the first 2 circles depends on distance between robot and
302 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", cd0.x, cd0.y, cd0.r);
306 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", cd1.x, cd1.y, cd1.r);
308 /* the third circle depends on angle between b0 and b1 */
315 if (angle_to_circles(&c01, NULL, b0, b1, a01))
317 dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", c01.x, c01.y, c01.r);
319 /* get the xy position, depending on algo */
320 if (ad_to_posxy_algo(pos, algo, b0, b1, &cd0, &cd1, &c01, a01, d0, d1) < 0)
323 /* now, we have the xy position, we can get angle thanks to
324 * the angles a0 and a1. Take the far beacon. */
326 *a = atan2(beacon1.y - pos->y, beacon1.x - pos->x) - a1;
328 *a = atan2(beacon0.y - pos->y, beacon0.x - pos->x) - a0;
336 /* get the angles of beacons from xy pos */
337 int8_t posxy_to_abs_angles(point_t pos, double *a0, double *a1,
338 double *a2, int err_num, float err_val)
340 *a0 = atan2(beacon0.y-pos.y, beacon0.x-pos.x);
341 *a1 = atan2(beacon1.y-pos.y, beacon1.x-pos.x);
342 *a2 = atan2(beacon2.y-pos.y, beacon2.x-pos.x);
344 if (err_num == 0 || err_num == 3)
345 *a0 += (err_val * M_PI/180.);
346 if (err_num == 1 || err_num == 3)
347 *a1 += (err_val * M_PI/180.);
348 if (err_num == 2 || err_num == 3)
349 *a2 += (err_val * M_PI/180.);
354 /* get the angles of beacons from xy pos */
355 int8_t posxy_to_angles(point_t pos, double *a01, double *a12,
356 double *a20, int err_num, float err_val)
359 posxy_to_abs_angles(pos, &a0, &a1, &a2, err_num, err_val);
374 int8_t process_move_error(double x, double y, double speed,
375 double period, double angle, double *err)
377 double a01, a12, a20;
386 /* from start to destination */
387 v.x = cos(angle) * speed * period;
388 v.y = sin(angle) * speed * period;
390 /* first process real pos */
391 posxy_to_angles(pos, &a01, &a12, &a20, -1, 0);
393 /* vector covered during measure of a0 and a1 */
394 u.x = v.x * a01 / (2*M_PI);
395 u.y = v.y * a01 / (2*M_PI);
396 pos2.x = pos.x + u.x;
397 pos2.y = pos.y + u.y;
399 /* vector covered during measure of a1 and a2 */
400 u.x = v.x * a12 / (2*M_PI);
401 u.y = v.y * a12 / (2*M_PI);
402 pos3.x = pos2.x + u.x;
403 pos3.y = pos2.y + u.y;
405 dprintf("p0: x=%2.2f y=%2.2f\n", pos.x, pos.y);
406 dprintf("p1: x=%2.2f y=%2.2f\n", pos2.x, pos2.y);
407 dprintf("p2: x=%2.2f y=%2.2f\n", pos3.x, pos3.y);
409 a0 = atan2(beacon0.y-pos.y, beacon0.x-pos.x);
410 a1 = atan2(beacon1.y-pos2.y, beacon1.x-pos2.x);
411 a2 = atan2(beacon2.y-pos3.y, beacon2.x-pos3.x);
423 if (angles_to_posxy(&tmp, a01, a12, a20))
425 *err = pt_norm(&tmp, &pos);
426 if (*err > 50.) /* saturate error to 5cm */
432 /* whole process is around 3ms on atmega128 at 16Mhz */
433 int main(int argc, char **argv)
436 double a01, a12, a20;
438 const char *mode = "nothing";
442 printf("bad args\n");
455 * angle2pos a0 a1 a2:
456 * (angles in radian, -pi < a < pi)
458 if (argc == 5 && strcmp(mode, "angle2pos") == 0) {
477 if (angles_to_posxy(&pos, a01, a12, a20) < 0)
479 printf("p0: x=%2.2f y=%2.2f\n", pos.x, pos.y);
484 * ad2pos a0 a1 d0 d1:
485 * (angles in radian, -pi < a < pi)
488 if (argc == 6 && strcmp(mode, "ad2pos") == 0) {
498 if (ad_to_posxya(&pos, &a, 0, &beacon0, &beacon1,
501 printf("p0: x=%2.2f y=%2.2f a=%2.2f\n", pos.x, pos.y, a);
505 if (argc == 4 && strcmp(mode, "simple_error") == 0) {
511 err_num = atof(argv[2]); /* which beacon sees an error */
512 err_val_deg = atof(argv[3]); /* how many degrees of error */
514 for (x=0; x<300; x++) {
515 for (y=0; y<210; y++) {
519 posxy_to_angles(pos, &a01, &a12, &a20,
520 err_num, err_val_deg);
521 if (angles_to_posxy(&tmp, a01, a12, a20))
523 err = pt_norm(&tmp, &pos);
524 if (err > 50.) /* saturate error to 5cm */
526 printf("%d %d %2.2f\n", x, y, err);
532 /* da_error algo errpercent errdeg */
533 if ((argc == 5 && strcmp(mode, "da_error") == 0) ||
534 (argc == 5 && strcmp(mode, "da_error_mm") == 0)) {
537 double err_val_percent;
539 double err, d0, d1, a;
541 algo = atoi(argv[2]);
542 err_val_percent = atof(argv[3]); /* how many % of error for dist */
543 err_val_mm = atof(argv[3]); /* how many mm of error for dist */
544 err_val_deg = atof(argv[4]); /* how many degrees of error */
546 for (x=0; x<300; x++) {
547 for (y=0; y<210; y++) {
551 posxy_to_abs_angles(pos, &a0, &a1, &a2,
553 d0 = pt_norm(&pos, &beacon0);
554 d1 = pt_norm(&pos, &beacon1);
555 if (strcmp(mode, "da_error") == 0) {
556 d0 += d0 * err_val_percent / 100.;
557 d1 += d1 * err_val_percent / 100.;
564 if (ad_to_posxya(&tmp, &a, algo, &beacon0, &beacon1,
568 err = pt_norm(&tmp, &pos);
569 if (err > 50.) /* saturate error to 5cm */
571 printf("%d %d %2.2f\n", x, y, err);
577 if ((argc == 5 || argc == 7)
578 && strcmp(argv[1], "move_error") == 0) {
580 double angle, speed, period, err;
582 speed = atof(argv[2]); /* speed in m/s ( = mm/ms) */
583 period = atof(argv[3]); /* period of turret in ms */
584 angle = atof(argv[4]); /* direction of moving */
587 process_move_error(atof(argv[5]), atof(argv[6]),
588 speed, period, angle, &err);
589 printf("%2.2f %2.2f %2.2f\n", atof(argv[5]),
594 for (x=0; x<300; x++) {
595 for (y=0; y<210; y++) {
598 if (process_move_error(pos.x, pos.y,
599 speed, period, angle,
602 printf("%d %d %2.2f\n", x, y, err);
608 printf("bad args\n");