weak current limit on spickles
[aversive.git] / projects / microb2010 / mainboard / strat_db.c
1 /*
2  *  Copyright Droids, Microb Technology (2010)
3  *
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.
8  *
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.
13  *
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
17  *
18  *  Revision : $Id: strat.c,v 1.6 2009-11-08 17:24:33 zer0 Exp $
19  *
20  *  Olivier MATZ <zer0@droids-corp.org>
21  */
22
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <math.h>
29
30 #include <aversive.h>
31 #include <aversive/pgmspace.h>
32
33 #include <ax12.h>
34 #include <uart.h>
35 #include <pwm_ng.h>
36 #include <clock_time.h>
37 #include <spi.h>
38
39 #include <pid.h>
40 #include <quadramp.h>
41 #include <control_system_manager.h>
42 #include <trajectory_manager.h>
43 #include <trajectory_manager_utils.h>
44 #include <trajectory_manager_core.h>
45 #include <vect_base.h>
46 #include <lines.h>
47 #include <polygon.h>
48 #include <obstacle_avoidance.h>
49 #include <blocking_detection_manager.h>
50 #include <robot_system.h>
51 #include <position_manager.h>
52
53 #include <diagnostic.h>
54
55 #include <rdline.h>
56 #include <parse.h>
57
58 #include "../common/i2c_commands.h"
59 #include "i2c_protocol.h"
60 #include "main.h"
61 #include "strat.h"
62 #include "strat_base.h"
63 #include "strat_corn.h"
64 #include "strat_db.h"
65 #include "strat_utils.h"
66 #include "sensor.h"
67 #include "actuator.h"
68
69 /* status of objects on area */
70 struct strat_db strat_db;
71
72 /* given an index, give the i coord */
73 static const uint8_t corn_coord_i[CORN_NB] = {
74         0, 0, 0, 2, 2, 2, 4, 4, 6,
75         6, 8, 8, 10, 10, 10, 12, 12, 12,
76 };
77
78 /* given an index, give the j coord */
79 static const uint8_t corn_coord_j[CORN_NB] = {
80         2, 4, 6, 3, 5, 7, 4, 6, 5,
81         7, 4, 6, 3, 5, 7, 2, 4, 6,
82 };
83
84 /* table to find the symetric idx */
85 static const uint8_t corn_sym[] = {
86         15, 16, 17, 12, 13, 14, 10, 11,
87         8, 9, 6, 7, 3, 4, 5, 0, 1, 2
88 };
89
90 #if 0 /* XXX maybe useless */
91 /* the 10 possible configurations for corn on the side */
92 static const uint8_t corn_side_confs[9][2] = {
93         { 1, 4 },
94         { 0, 4 },
95         { 2, 4 },
96         { 2, 3 },
97         { 0, 3 },
98         { 1, 3 },
99         { 1, 6 },
100         { 0, 6 },
101         { 2, 6 },
102 };
103
104 /* the 4 possible configurations for corn on center */
105 static const uint8_t corn_center_confs[4][2] = {
106         { 5, 8 },
107         { 7, 8 },
108         { 5, 9 },
109         { 7, 8 },
110 };
111 #endif
112
113 /* in these groups, only one black cob */
114 static const int8_t corn_group1[] = { 0, 1, 2, -1, };
115 static const int8_t corn_group2[] = { 3, 4, 6, -1, };
116 static const int8_t corn_group3[] = { 5, 7, -1, };
117 static const int8_t corn_group4[] = { 8, 9, -1, };
118 static const int8_t corn_group5[] = { 11, 14, -1, };
119 static const int8_t corn_group6[] = { 10, 12, 13, -1, };
120 static const int8_t corn_group7[] = { 15, 16, 17, -1, };
121
122 static const int8_t *corn_groups[] = {
123         corn_group1,
124         corn_group2,
125         corn_group3,
126         corn_group4,
127         corn_group5,
128         corn_group6,
129         corn_group7,
130         NULL,
131 };
132
133 /* given an index, give the i coord */
134 static const uint8_t tomato_coord_i[TOMATO_NB] = {
135         0, 0, 2, 2, 4, 4, 6, 6,
136         8, 8, 10, 10, 12, 12,
137 };
138
139 /* given an index, give the j coord */
140 static const uint8_t tomato_coord_j[TOMATO_NB] = {
141         3, 5, 4, 6, 5, 7, 4, 6, 5, 7, 4, 6, 3, 5,
142 };
143
144 /******** Generic waypoint */
145
146 /* return the xy coords of a waypoint given its ij coords. */
147 int8_t ijcoord_to_xycoord(uint8_t i, uint8_t j, int16_t *x, int16_t *y)
148 {
149         if (i >= WAYPOINTS_NBX && j >= WAYPOINTS_NBY)
150                 return -1;
151         *x = (OFFSET_CORN_X + i*STEP_CORN_X);
152         *y = COLOR_Y(OFFSET_CORN_Y + j*STEP_CORN_Y);
153         return 0;
154 }
155
156 /* return the nearest waypoint that is not a corn: xp and yp contains
157  * the input and output, and ip, jp are only outputs. return 0 on
158  * success. */
159 int8_t xycoord_to_ijcoord(int16_t *xp, int16_t *yp, uint8_t *ip, uint8_t *jp)
160 {
161         int16_t x, y;
162         uint8_t i, j;
163
164         x = *xp;
165         y = *yp;
166
167         x -= OFFSET_CORN_X;
168         x += (STEP_CORN_X/2);
169         i = x / STEP_CORN_X;
170
171         y = COLOR_Y(y);
172         y -= OFFSET_CORN_Y;
173         if ((i & 1) == 1) {
174                 j = y / STEP_CORN_Y;
175         }
176         else if ((i & 3) == 0) {
177                 j = y / (STEP_CORN_Y*2);
178                 j = j*2 + 1;
179         }
180         else {
181                 y += (STEP_CORN_Y);
182                 j = y / (STEP_CORN_Y*2);
183                 j = j*2;
184         }
185
186         if (ijcoord_to_xycoord(i, j, &x, &y) < 0)
187                 return -1;
188
189         if (strat_db.wp_table[i][j].type != WP_TYPE_WAYPOINT &&
190             strat_db.wp_table[i][j].type != WP_TYPE_TOMATO)
191                 return -1;
192
193         *xp = x;
194         *yp = y;
195         *ip = i;
196         *jp = j;
197
198         return 0;
199 }
200
201 /******** CORN */
202
203 /* return the index of a corn given its i,j coords. */
204 int8_t ijcoord_to_corn_idx(uint8_t i, uint8_t j)
205 {
206         uint8_t n;
207         for (n = 0; n < CORN_NB; n ++) {
208                 if (i == corn_coord_i[n] &&
209                     j == corn_coord_j[n])
210                         return n;
211         }
212         return -1;
213 }
214
215 /* return the i,j coords of a corn given its index */
216 int8_t corn_idx_to_ijcoord(uint8_t idx, uint8_t *i, uint8_t *j)
217 {
218         if (idx >= CORN_NB)
219                 return -1;
220         *i = corn_coord_i[idx];
221         *j = corn_coord_j[idx];
222         return 0;
223 }
224
225 /* return the index of a corn given its x,y coords. */
226 int8_t corn_idx_to_xycoord(uint8_t idx, int16_t *x, int16_t *y)
227 {
228         uint8_t i, j;
229         if (corn_idx_to_ijcoord(idx, &i, &j) < 0)
230                 return -1;
231         if (ijcoord_to_xycoord(i, j, x, y) < 0)
232                 return -1;
233         return 0;
234 }
235
236 #define CORN_MARGIN 200
237 /* return the index of the closest corn at these coordinates. If the
238  * corn is really too far (~20cm), return NULL. The x and y pointer are
239  * updated with the real position of the corn */
240 struct waypoint_db *xycoord_to_corn_idx(int16_t *xp, int16_t *yp)
241 {
242         int16_t x, y;
243         uint8_t i, j;
244         double d;
245
246         x = *xp;
247         y = *yp;
248
249         x -= OFFSET_CORN_X;
250         x += STEP_CORN_X;
251         x /= (STEP_CORN_X*2);
252
253         y = COLOR_Y(y);
254         y -= OFFSET_CORN_Y;
255         y += STEP_CORN_Y;
256         if ((x & 1) == 1)
257                 y -= STEP_CORN_Y;
258         y /= (STEP_CORN_Y*2);
259
260         i = (x * 2);
261         j = (y * 2) + (x & 1);
262
263         if (ijcoord_to_xycoord(i, j, &x, &y) < 0)
264                 return NULL;
265
266         if (strat_db.wp_table[i][j].type != WP_TYPE_CORN)
267                 return NULL;
268
269         d = xy_norm(*xp, *yp, x, y);
270
271         if (d > CORN_MARGIN)
272                 return NULL;
273
274         *xp = x;
275         *yp = y;
276
277         return &strat_db.wp_table[i][j];
278 }
279
280 /* return true if 'idx' is in group */
281 static uint8_t is_in_group(const int8_t *group, uint8_t idx)
282 {
283         const int8_t *pidx;
284         for (pidx = group; *pidx != -1; pidx++) {
285                 if (*pidx == idx) {
286                         return 1;
287                 }
288         }
289         return 0;
290 }
291
292 /* return the number of cob of that color in the group */
293 static uint8_t count_in_group(const int8_t *group, uint8_t color)
294 {
295         const int8_t *pidx;
296         struct waypoint_db *wp;
297         uint8_t count = 0;
298
299         for (pidx = &group[0]; *pidx != -1; pidx++) {
300                 wp = strat_db.corn_table[*pidx];
301                 if (wp->corn.color == color)
302                         count ++;
303         }
304         return count;
305 }
306
307 /* set all unkown cobs to specified color */
308 static void set_unknown_in_group(const int8_t *group, uint8_t color)
309 {
310         const int8_t *pidx;
311         struct waypoint_db *wp;
312
313         for (pidx = &group[0]; *pidx != -1; pidx++) {
314                 wp = strat_db.corn_table[*pidx];
315                 if (wp->corn.color == I2C_COB_UNKNOWN)
316                         wp->corn.color = color;
317         }
318 }
319
320 /* depending on which cob is set (and its color), set the color of
321  * other cobs */
322 static void corn_deduct_other(uint8_t idx, uint8_t color)
323 {
324         const int8_t **pgroup;
325
326         for (pgroup = &corn_groups[0]; *pgroup; pgroup++) {
327                 if (!is_in_group(*pgroup, idx))
328                         continue;
329                 if (color == I2C_COB_BLACK) {
330                         set_unknown_in_group(*pgroup, I2C_COB_WHITE);
331                 }
332                 else if (color == I2C_COB_WHITE) {
333                         if (count_in_group(*pgroup, I2C_COB_UNKNOWN) == 1)
334                                 set_unknown_in_group(*pgroup, I2C_COB_BLACK);
335                 }
336         }
337 }
338
339 /* set color of a corn
340  * type is I2C_COB_BLACK, I2C_COB_WHITE, I2C_COB_UNKNOWN
341  * it will update the symetric corn if != UNKOWN
342  * it will also deduct color of some other cobs */
343 void corn_set_color(struct waypoint_db *wp, uint8_t color)
344 {
345         uint8_t symidx;
346
347         if (wp->corn.color != I2C_COB_UNKNOWN)
348                 return;
349         wp->corn.color = color;
350         if (color == I2C_COB_UNKNOWN)
351                 return;
352         corn_deduct_other(wp->corn.idx, color);
353         symidx = corn_get_sym_idx(wp->corn.idx);
354         strat_db.corn_table[symidx]->corn.color = color;
355         corn_deduct_other(symidx, color);
356 }
357
358
359 /* return the idx of the symetric corn */
360 int8_t corn_get_sym_idx(int8_t i)
361 {
362         if (i >= CORN_NB)
363                 return -1;
364         return corn_sym[i];
365 }
366
367 /*********** TOMATO */
368
369 /* return the index of a tomato given its i,j coords. */
370 int8_t ijcoord_to_tomato_idx(uint8_t i, uint8_t j)
371 {
372         uint8_t n;
373         for (n = 0; n < TOMATO_NB; n ++) {
374                 if (i == tomato_coord_i[n] &&
375                     j == tomato_coord_j[n])
376                         return n;
377         }
378         return -1;
379 }
380
381 /* return the i,j coords of a tomato given its index */
382 int8_t tomato_idx_to_ijcoord(uint8_t idx, uint8_t *i, uint8_t *j)
383 {
384         if (idx >= TOMATO_NB)
385                 return -1;
386         *i = tomato_coord_i[idx];
387         *j = tomato_coord_j[idx];
388         return 0;
389 }
390
391 /* return the index of a tomato given its x,y coords. */
392 int8_t tomato_idx_to_xycoord(uint8_t idx, int16_t *x, int16_t *y)
393 {
394         uint8_t i, j;
395         if (tomato_idx_to_ijcoord(idx, &i, &j) < 0)
396                 return -1;
397         if (ijcoord_to_xycoord(i, j, x, y) < 0)
398                 return -1;
399         return 0;
400 }
401
402 #define TOMATO_MARGIN 200
403 /* return the index of the closest tomato at these coordinates. If the
404  * tomato is really too far (~20cm), return NULL. The x and y pointer are
405  * updated with the real position of the tomato */
406 struct waypoint_db *xycoord_to_tomato_idx(int16_t *x, int16_t *y)
407 {
408         uint8_t idx = -1, n;
409         int16_t d, x_tomato, y_tomato;
410         int16_t x_tomato_min = 0, y_tomato_min = 0;
411         int16_t d_min = 0;
412
413         /* XXX does it work when we are blue ? */
414         for (n = 0; n < TOMATO_NB; n ++) {
415                 tomato_idx_to_xycoord(n, &x_tomato, &y_tomato);
416                 d = xy_norm(x_tomato, y_tomato, *x, *y);
417                 if (d < TOMATO_MARGIN && (d_min == 0 || d < d_min)) {
418                         d_min = d;
419                         idx = n;
420                         x_tomato_min = x_tomato;
421                         y_tomato_min = y_tomato;
422                 }
423         }
424         if (d_min == 0)
425                 return NULL;
426
427         *x = x_tomato_min;
428         *y = y_tomato_min;
429
430         return strat_db.tomato_table[idx];
431 }
432
433 /*
434  * Init internal database. The initialization is done with UNKNOWN
435  * corn with all objects present
436  */
437 void strat_db_init(void)
438 {
439         struct waypoint_db *wp;
440         int8_t idx;
441         int8_t i, j;
442
443         memset(&strat_db.wp_table, 0, sizeof(strat_db.wp_table));
444
445         /* corn table */
446         for (i=0; i<CORN_NB; i++) {
447                 strat_db.corn_table[i] =
448                         &strat_db.wp_table[corn_coord_i[i]][corn_coord_j[i]];
449         }
450         /* tomato table */
451         for (i=0; i<TOMATO_NB; i++) {
452                 strat_db.tomato_table[i] =
453                         &strat_db.wp_table[tomato_coord_i[i]][tomato_coord_j[i]];
454         }
455
456         strat_db.our_oranges_count = 6;
457         strat_db.opp_oranges_count = 6;
458
459         for (i=0; i<WAYPOINTS_NBX; i++) {
460
461                 for (j=0; j<WAYPOINTS_NBY; j++) {
462                         wp = &strat_db.wp_table[i][j];
463
464                         /* default type */
465                         wp->type = WP_TYPE_WAYPOINT;
466
467                         /* mark dangerous points */
468                         if (i == 0 || i == (WAYPOINTS_NBX-1))
469                                 wp->dangerous = 1;
470                         if ((i & 1) == 0 && j == (WAYPOINTS_NBY-1))
471                                 wp->dangerous = 1;
472
473                         /* on border, unreachable wp */
474                         if ((i & 1) == 1 && j == (WAYPOINTS_NBY-1)) {
475                                 wp->type = WP_TYPE_OBSTACLE;
476                                 continue;
477                         }
478
479                         /* hill */
480                         if (i >= 2 && i < (WAYPOINTS_NBX-2) && j < 2) {
481                                 wp->type = WP_TYPE_OBSTACLE;
482                                 continue;
483                         }
484
485                         /* corn */
486                         idx = ijcoord_to_corn_idx(i, j);
487                         if (idx >= 0) {
488                                 wp->type = WP_TYPE_CORN;
489                                 wp->present = 1;
490                                 wp->corn.idx = idx;
491                                 wp->corn.color = I2C_COB_UNKNOWN;
492                                 continue;
493                         }
494
495                         /* tomato */
496                         idx = ijcoord_to_tomato_idx(i, j);
497                         if (idx >= 0) {
498                                 wp->type = WP_TYPE_TOMATO;
499                                 wp->present = 1;
500                                 wp->tomato.idx = idx;
501                                 continue;
502                         }
503                 }
504         }
505 }
506
507 /* dump infos about area and objects */
508 void strat_db_dump(const char *caller)
509 {
510         uint8_t i;
511         struct waypoint_db *wp;
512
513         if (strat_db.dump_enabled == 0)
514                 return;
515
516         printf_P(PSTR("DB dump from <%s>\r\n"), caller);
517         for (i=0; i<CORN_NB; i++) {
518                 wp = strat_db.corn_table[i];
519                 printf_P(PSTR("corn%d: present=%d opp=%d "),
520                          i, wp->present, wp->opp_visited);
521                 if (wp->corn.color == I2C_COB_UNKNOWN)
522                         printf_P(PSTR("unknown"));
523                 else if (wp->corn.color == I2C_COB_BLACK)
524                         printf_P(PSTR("black"));
525                 else if (wp->corn.color == I2C_COB_WHITE)
526                         printf_P(PSTR("white"));
527                 printf_P(PSTR("\r\n"));
528         }
529
530         for (i=0; i<TOMATO_NB; i++) {
531                 wp = strat_db.tomato_table[i];
532                 printf_P(PSTR("tomato%d: present=%d opp=%d\r\n"),
533                          i, wp->present, wp->opp_visited);
534         }
535 }