prepare cobboard and ballboard
[aversive.git] / projects / microb2010 / tests / beacon_tsop / trigo.c
index 391043c..df45edf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright Droids Corporation (2010)
+ *  Copyright Droids Corporation (2009)
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -15,7 +15,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- *  Olivier MATZ <zer0@droids-corp.org>
+ *  Revision : $Id: f16.h,v 1.6.4.3 2008-05-10 15:06:26 zer0 Exp $
+ *
  */
 
 #include <stdio.h>
 static int dprint = 0;
 #define dprintf(args...) if (dprint) printf(args)
 
+#define AREA_X 3000
+#define AREA_Y 2100
+
+#define ANGLE_EPSILON 0.005
+
 const point_t beacon0 = { 0, 1050 };
 const point_t beacon1 = { 3000, 0 };
 const point_t beacon2 = { 3000, 2100 };
 
+static inline double abs_dbl(double x)
+{
+       if (x > 0)
+               return x;
+       else
+               return -x;
+}
+
 /* Fill the 2 circles pointer given as parameter, each of those cross
  * both beacons b1 and b2. From any point of these circles (except b1
  * and b2), we see b1 and b2 with the angle of a_rad (which must be
@@ -79,8 +93,8 @@ int8_t angle_to_circles(circle_t *c1, circle_t *c2,
        vect_t v;
        float l, d;
 
-       /* reject negative or too small angles */
-       if (a_rad <= 0.01)
+       /* reject too small angles */
+       if (a_rad <= 0.01 && a_rad >= -0.01)
                return -1;
 
        /* get position of O */
@@ -159,22 +173,190 @@ int8_t angles_to_posxy(point_t *pos, double a01, double a12, double a20)
        return 0;
 }
 
-/* get the angles of beacons from xy pos */
-int8_t posxy_to_angles(point_t pos, double *a01, double *a12,
-                      double *a20, int err_num, float err_val)
+static inline int8_t is_pt_in_area(point_t pt)
 {
-       double a0, a1, a2;
+       if (pt.x < 0 || pt.y < 0)
+               return 0;
+       if (pt.x > AREA_X || pt.y > AREA_Y)
+               return 0;
+       return 1;
+}
 
-       a0 = atan2(beacon0.y-pos.y, beacon0.x-pos.x);
-       a1 = atan2(beacon1.y-pos.y, beacon1.x-pos.x);
-       a2 = atan2(beacon2.y-pos.y, beacon2.x-pos.x);
+/* intersect the circle formed by one distance info with the circle
+ * crossing the 2 beacons */
+static int8_t
+ad_to_posxy_one(point_t *pos,
+               const point_t *b0, const point_t *b1, /* beacon position */
+               const circle_t *cd, const circle_t *c01, /* circles to intersect */
+               double a01) /* seen angle of beacons */
+{
+       double tmp_a01_p1, tmp_a01_p2;
+       point_t p1, p2;
+       uint8_t p1_ok=0, p2_ok=0;
+
+       if (circle_intersect(c01, cd, &p1, &p2) == 0)
+               return -1;
+
+       dprintf("p1: x=%2.2f y=%2.2f\n", p1.x, p1.y);
+       dprintf("p2: x=%2.2f y=%2.2f\n", p2.x, p2.y);
+
+       dprintf("real a01: %2.2f\n", a01);
+
+       tmp_a01_p1 = atan2(b1->y-p1.y, b1->x-p1.x) -
+               atan2(b0->y-p1.y, b0->x-p1.x);
+       if (tmp_a01_p1 > M_PI)
+               tmp_a01_p1 -= 2*M_PI;
+       if (tmp_a01_p1 < -M_PI)
+               tmp_a01_p1 += 2*M_PI;
+       dprintf("a01-1: %2.2f\n", tmp_a01_p1);
+
+       tmp_a01_p2 = atan2(b1->y-p2.y, b1->x-p2.x) -
+               atan2(b0->y-p2.y, b0->x-p2.x);
+       if (tmp_a01_p2 > M_PI)
+               tmp_a01_p2 -= 2*M_PI;
+       if (tmp_a01_p2 < -M_PI)
+               tmp_a01_p2 += 2*M_PI;
+       dprintf("a01-2: %2.2f\n", tmp_a01_p2);
+
+       /* in some conditions, we already know the position of the
+        * robot at this step */
+       p1_ok = is_pt_in_area(p1) &&
+               abs_dbl(tmp_a01_p1 - a01) < ANGLE_EPSILON;
+
+       p2_ok = is_pt_in_area(p2) &&
+               abs_dbl(tmp_a01_p2 - a01) < ANGLE_EPSILON;
+       if (!p1_ok && p2_ok) {
+               *pos = p2;
+               return 0;
+       }
+       if (p1_ok && !p2_ok) {
+               *pos = p1;
+               return 0;
+       }
+       return -1;
+}
+
+static int8_t
+ad_to_posxy_algo(point_t *pos, int algo,
+                const point_t *b0, const point_t *b1, /* beacon position */
+                const circle_t *cd0, const circle_t *cd1, const circle_t *c01, /* circles to intersect */
+                double a01, /* seen angle of beacons */
+                double d0, double d1 /* distance to beacons */ )
+
+{
+       switch (algo) {
+
+               /* take the closer beacon first */
+       case 0:
+               if (d0 < d1) {
+                       if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
+                               return 0;
+                       if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
+                               return 0;
+                       return -1;
+               }
+               else {
+                       if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
+                               return 0;
+                       if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
+                               return 0;
+                       return -1;
+               }
+               break;
+       case 1:
+               /* b0 only */
+               if (ad_to_posxy_one(pos, b0, b1, cd0, c01, a01) == 0)
+                       return 0;
+               break;
+       case 2:
+               /* b0 only */
+               if (ad_to_posxy_one(pos, b0, b1, cd1, c01, a01) == 0)
+                       return 0;
+               break;
+       default:
+               break;
+       }
+       /* not found */
+       return -1;
+}
+
+/* get the position and angle of the robot from the angle of the 2
+ * beacons, and the distance of 2 beacons */
+int8_t
+ad_to_posxya(point_t *pos, double *a, int algo,
+            const point_t *b0, const point_t *b1, /* beacon position */
+            double a0, double a1, /* seen angle of beacons */
+            double d0, double d1 /* distance to beacons */ )
+{
+       circle_t cd0, cd1, c01;
+       double a01;
+
+       dprintf("algo=%d a0=%2.2f a1=%2.2f d0=%2.2f d1=%2.2f\n",
+               algo, a0, a1, d0, d1);
+
+       /* the first 2 circles depends on distance between robot and
+        * beacons */
+       cd0.x = b0->x;
+       cd0.y = b0->y;
+       cd0.r = d0;
+       dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", cd0.x, cd0.y, cd0.r);
+       cd1.x = b1->x;
+       cd1.y = b1->y;
+       cd1.r = d1;
+       dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", cd1.x, cd1.y, cd1.r);
+
+       /* the third circle depends on angle between b0 and b1 */
+       a01 = a1-a0;
+       if (a01 < -M_PI)
+               a01 += 2*M_PI;
+       if (a01 > M_PI)
+               a01 -= 2*M_PI;
+
+       if (angle_to_circles(&c01, NULL, b0, b1, a01))
+               return -1;
+       dprintf("circle: x=%2.2f y=%2.2f r=%2.2f\n", c01.x, c01.y, c01.r);
+
+       /* get the xy position, depending on algo */
+       if (ad_to_posxy_algo(pos, algo, b0, b1, &cd0, &cd1, &c01, a01, d0, d1) < 0)
+               return -1;
+
+       /* now, we have the xy position, we can get angle thanks to
+        * the angles a0 and a1. Take the far beacon. */
+       if (d0 < d1)
+               *a = atan2(beacon1.y - pos->y, beacon1.x - pos->x) - a1;
+       else
+               *a = atan2(beacon0.y - pos->y, beacon0.x - pos->x) - a0;
+       if (*a < -M_PI)
+               *a += 2*M_PI;
+       if (*a > M_PI)
+               *a -= 2*M_PI;
+       return 0;
+}
+
+/* get the angles of beacons from xy pos */
+int8_t posxy_to_abs_angles(point_t pos, double *a0, double *a1,
+                          double *a2, int err_num, float err_val)
+{
+       *a0 = atan2(beacon0.y-pos.y, beacon0.x-pos.x);
+       *a1 = atan2(beacon1.y-pos.y, beacon1.x-pos.x);
+       *a2 = atan2(beacon2.y-pos.y, beacon2.x-pos.x);
 
        if (err_num == 0 || err_num == 3)
-               a0 += (err_val * M_PI/180.);
+               *a0 += (err_val * M_PI/180.);
        if (err_num == 1 || err_num == 3)
-               a1 += (err_val * M_PI/180.);
+               *a1 += (err_val * M_PI/180.);
        if (err_num == 2 || err_num == 3)
-               a2 += (err_val * M_PI/180.);
+               *a2 += (err_val * M_PI/180.);
+
+       return 0;
+}
+
+/* get the angles of beacons from xy pos */
+int8_t posxy_to_angles(point_t pos, double *a01, double *a12,
+                      double *a20, int err_num, float err_val)
+{
+       double a0, a1, a2;
+       posxy_to_abs_angles(pos, &a0, &a1, &a2, err_num, err_val);
 
        *a01 = a1-a0;
        if (*a01 < 0)
@@ -245,3 +427,185 @@ int8_t process_move_error(double x, double y, double speed,
                *err = 50.;
        return 0;
 }
+
+#if 0
+/* whole process is around 3ms on atmega128 at 16Mhz */
+int main(int argc, char **argv)
+{
+       double a0, a1, a2;
+       double a01, a12, a20;
+       point_t pos, tmp;
+       const char *mode = "nothing";
+
+#ifdef HOST_VERSION
+       if (argc < 2) {
+               printf("bad args\n");
+               return -1;
+       }
+       mode = argv[1];
+#else
+       mode = "angle2pos";
+       argc = 5;
+       a0 = -1.;
+       a1 = 1.65;
+       a2 = 3.03;
+#endif
+
+       /*
+        * angle2pos a0 a1 a2:
+        *   (angles in radian, -pi < a < pi)
+        */
+       if (argc == 5 && strcmp(mode, "angle2pos") == 0) {
+#ifdef HOST_VERSION
+               dprint = 1;
+               a0 = atof(argv[2]);
+               a1 = atof(argv[3]);
+               a2 = atof(argv[4]);
+#endif
+
+               /* */
+               a01 = a1-a0;
+               if (a01 < 0)
+                       a01 += 2*M_PI;
+               a12 = a2-a1;
+               if (a12 < 0)
+                       a12 += 2*M_PI;
+               a20 = a0-a2;
+               if (a20 < 0)
+                       a20 += 2*M_PI;
+
+               if (angles_to_posxy(&pos, a01, a12, a20) < 0)
+                       return -1;
+               printf("p0: x=%2.2f y=%2.2f\n", pos.x, pos.y);
+               return 0;
+       }
+
+       /*
+        * ad2pos a0 a1 d0 d1:
+        *   (angles in radian, -pi < a < pi)
+        *   (distances in mm)
+        */
+       if (argc == 6 && strcmp(mode, "ad2pos") == 0) {
+               double a, d0, d1;
+
+               dprint = 1;
+               a0 = atof(argv[2]);
+               a1 = atof(argv[3]);
+               d0 = atof(argv[4]);
+               d1 = atof(argv[5]);
+
+               /* */
+               if (ad_to_posxya(&pos, &a, 0, &beacon0, &beacon1,
+                                a0, a1, d0, d1) < 0)
+                       return -1;
+               printf("p0: x=%2.2f y=%2.2f a=%2.2f\n", pos.x, pos.y, a);
+               return 0;
+       }
+
+       if (argc == 4 && strcmp(mode, "simple_error") == 0) {
+               int x, y;
+               int err_num;
+               double err_val_deg;
+               double err;
+
+               err_num = atof(argv[2]); /* which beacon sees an error */
+               err_val_deg = atof(argv[3]); /* how many degrees of error */
+
+               for (x=0; x<300; x++) {
+                       for (y=0; y<210; y++) {
+
+                               pos.x = x*10;
+                               pos.y = y*10;
+                               posxy_to_angles(pos, &a01, &a12, &a20,
+                                               err_num, err_val_deg);
+                               if (angles_to_posxy(&tmp, a01, a12, a20))
+                                       continue;
+                               err = pt_norm(&tmp, &pos);
+                               if (err > 50.) /* saturate error to 5cm */
+                                       err = 50.;
+                               printf("%d %d %2.2f\n", x, y, err);
+                       }
+               }
+               return 0;
+       }
+
+       /* da_error algo errpercent errdeg */
+       if ((argc == 5 && strcmp(mode, "da_error") == 0) ||
+           (argc == 5 && strcmp(mode, "da_error_mm") == 0)) {
+               int x, y, algo;
+               double err_val_deg;
+               double err_val_percent;
+               double err_val_mm;
+               double err, d0, d1, a;
+
+               algo = atoi(argv[2]);
+               err_val_percent = atof(argv[3]); /* how many % of error for dist */
+               err_val_mm = atof(argv[3]); /* how many mm of error for dist */
+               err_val_deg = atof(argv[4]); /* how many degrees of error */
+
+               for (x=0; x<300; x++) {
+                       for (y=0; y<210; y++) {
+
+                               pos.x = x*10;
+                               pos.y = y*10;
+                               posxy_to_abs_angles(pos, &a0, &a1, &a2,
+                                                   0, err_val_deg);
+                               d0 = pt_norm(&pos, &beacon0);
+                               d1 = pt_norm(&pos, &beacon1);
+                               if (strcmp(mode, "da_error") == 0) {
+                                       d0 += d0 * err_val_percent / 100.;
+                                       d1 += d1 * err_val_percent / 100.;
+                               }
+                               else {
+                                       d0 += err_val_mm;
+                                       d1 += err_val_mm;
+                               }
+
+                               if (ad_to_posxya(&tmp, &a, algo, &beacon0, &beacon1,
+                                                a0, a1, d0, d1) < 0)
+                                       continue;
+
+                               err = pt_norm(&tmp, &pos);
+                               if (err > 50.) /* saturate error to 5cm */
+                                       err = 50.;
+                               printf("%d %d %2.2f\n", x, y, err);
+                       }
+               }
+               return 0;
+       }
+
+       if ((argc == 5 || argc == 7)
+           && strcmp(argv[1], "move_error") == 0) {
+               int x, y;
+               double angle, speed, period, err;
+
+               speed = atof(argv[2]); /* speed in m/s ( = mm/ms) */
+               period = atof(argv[3]); /* period of turret in ms */
+               angle = atof(argv[4]); /* direction of moving */
+               if (argc == 7) {
+                       dprint = 1;
+                       process_move_error(atof(argv[5]), atof(argv[6]),
+                                          speed, period, angle, &err);
+                       printf("%2.2f %2.2f %2.2f\n", atof(argv[5]),
+                              atof(argv[6]), err);
+                       return 0;
+               }
+
+               for (x=0; x<300; x++) {
+                       for (y=0; y<210; y++) {
+                               pos.x = x*10;
+                               pos.y = y*10;
+                               if (process_move_error(pos.x, pos.y,
+                                                      speed, period, angle,
+                                                      &err) < 0)
+                                       continue;
+                               printf("%d %d %2.2f\n", x, y, err);
+                       }
+               }
+               return 0;
+       }
+
+       printf("bad args\n");
+       return -1;
+}
+#endif