wait obstacle -- c nul en fait
[aversive.git] / projects / microb2010 / mainboard / strat_avoid.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 <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <math.h>
28
29 #include <aversive.h>
30 #include <aversive/pgmspace.h>
31 #include <aversive/error.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_db.h"
63 #include "strat_base.h"
64 #include "strat_corn.h"
65 #include "strat_avoid.h"
66 #include "strat_utils.h"
67 #include "sensor.h"
68 #include "actuator.h"
69
70 //#define VERBOSE
71
72 #ifdef VERBOSE
73 #define DPR(fmt, ...) printf_P(PSTR(fmt), ##__VA_ARGS__)
74 #else
75 #define DPR(args...) do {} while (0)
76 #endif
77
78 struct circuit {
79         const char *name;
80         uint8_t len;
81         const struct wp_coord *path;
82 };
83
84 const struct wp_coord butterfly_tab[] = {
85         { .i = 11, .j = 6, },
86         { .i = 10, .j = 6, },
87         { .i = 9, .j = 5, },
88         { .i = 8, .j = 5, },
89         { .i = 7, .j = 4, },
90         { .i = 6, .j = 4, },
91         { .i = 5, .j = 3, },
92         { .i = 4, .j = 3, },
93         { .i = 3, .j = 2, },
94         { .i = 2, .j = 2, },
95         { .i = 1, .j = 1, },
96         { .i = 1, .j = 2, },
97         { .i = 1, .j = 3, },
98         { .i = 1, .j = 4, },
99         { .i = 1, .j = 5, },
100         { .i = 1, .j = 6, },
101         { .i = 2, .j = 6, },
102         { .i = 3, .j = 5, },
103         { .i = 4, .j = 5, },
104         { .i = 5, .j = 4, },
105         { .i = 6, .j = 4, },
106         { .i = 7, .j = 3, },
107         { .i = 8, .j = 3, },
108         { .i = 9, .j = 2, },
109         { .i = 10, .j = 2, },
110         { .i = 11, .j = 1, },
111         { .i = 11, .j = 2, },
112         { .i = 11, .j = 3, },
113         { .i = 11, .j = 4, },
114         { .i = 11, .j = 5, },
115         { .i = 11, .j = 6, },
116 };
117
118 const struct circuit butterfly_circuit = {
119         .name = "butterfly",
120         .len = sizeof(butterfly_tab)/sizeof(struct wp_coord),
121         .path = butterfly_tab,
122 };
123
124 const struct wp_coord losange_tab[] = {
125         { .i = 11, .j = 6, },
126         { .i = 10, .j = 6, },
127         { .i = 9, .j = 5, },
128         { .i = 9, .j = 4, },
129         { .i = 9, .j = 3, },
130         { .i = 10, .j = 4, },
131         { .i = 11, .j = 4, },
132         { .i = 11, .j = 5, },
133         { .i = 11, .j = 6, },
134 };
135
136 const struct circuit losange_circuit = {
137         .name = "losange",
138         .len = sizeof(losange_tab)/sizeof(struct wp_coord),
139         .path = losange_tab,
140 };
141
142 const struct wp_coord triangle_tab[] = {
143         { .i = 11, .j = 6, },
144         { .i = 10, .j = 6, },
145         { .i = 9, .j = 5, },
146         { .i = 8, .j = 5, },
147         { .i = 7, .j = 4, },
148         { .i = 6, .j = 4, },
149         { .i = 7, .j = 3, },
150         { .i = 8, .j = 3, },
151         { .i = 9, .j = 2, },
152         { .i = 10, .j = 2, },
153         { .i = 11, .j = 1, },
154         { .i = 11, .j = 2, },
155         { .i = 11, .j = 3, },
156         { .i = 11, .j = 4, },
157         { .i = 11, .j = 5, },
158         { .i = 11, .j = 6, },
159 };
160
161 const struct circuit triangle_circuit = {
162         .name = "triangle",
163         .len = sizeof(triangle_tab)/sizeof(struct wp_coord),
164         .path = triangle_tab,
165 };
166
167 const struct wp_coord answer_d_tab[] = {
168         { .i = 11, .j = 6, },
169         { .i = 11, .j = 5, },
170         { .i = 11, .j = 4, },
171         { .i = 11, .j = 3, },
172         { .i = 11, .j = 2, },
173         { .i = 11, .j = 1, },
174         { .i = 10, .j = 2, },
175         { .i = 9, .j = 2, },
176         { .i = 8, .j = 3, },
177         { .i = 9, .j = 3, },
178         { .i = 10, .j = 4, },
179         { .i = 11, .j = 4, },
180         { .i = 11, .j = 5, },
181         { .i = 11, .j = 6, },
182 };
183
184 const struct circuit answer_d_circuit = {
185         .name = "answer_d",
186         .len = sizeof(answer_d_tab)/sizeof(struct wp_coord),
187         .path = answer_d_tab,
188 };
189
190 const struct wp_coord h_lambda_tab[] = {
191         { .i = 11, .j = 6, },
192         { .i = 10, .j = 6, },
193         { .i = 9, .j = 5, },
194         { .i = 8, .j = 5, },
195         { .i = 7, .j = 4, },
196         { .i = 6, .j = 4, },
197         { .i = 5, .j = 3, },
198         { .i = 5, .j = 4, },
199         { .i = 5, .j = 5, },
200         { .i = 5, .j = 6, },
201         { .i = 6, .j = 6, },
202         { .i = 7, .j = 5, },
203         { .i = 8, .j = 5, },
204         { .i = 9, .j = 5, },
205         { .i = 10, .j = 6, },
206         { .i = 11, .j = 6, },
207 };
208
209 const struct circuit h_lambda_circuit = {
210         .name = "h_lambda",
211         .len = sizeof(h_lambda_tab)/sizeof(struct wp_coord),
212         .path = h_lambda_tab,
213 };
214
215 const struct wp_coord asym_butterfly_tab[] = {
216         { .i = 11, .j = 6, },
217         { .i = 10, .j = 6, },
218         { .i = 9, .j = 5, },
219         { .i = 8, .j = 5, },
220         { .i = 7, .j = 4, },
221         { .i = 6, .j = 4, },
222         { .i = 5, .j = 3, },
223         { .i = 4, .j = 3, },
224         { .i = 3, .j = 2, },
225         { .i = 3, .j = 3, },
226         { .i = 3, .j = 4, },
227         { .i = 3, .j = 5, },
228         { .i = 4, .j = 5, },
229         { .i = 5, .j = 4, },
230         { .i = 6, .j = 4, },
231         { .i = 7, .j = 3, },
232         { .i = 8, .j = 3, },
233         { .i = 9, .j = 2, },
234         { .i = 10, .j = 2, },
235         { .i = 11, .j = 1, },
236         { .i = 11, .j = 2, },
237         { .i = 11, .j = 3, },
238         { .i = 11, .j = 4, },
239         { .i = 11, .j = 5, },
240         { .i = 11, .j = 6, },
241 };
242
243 const struct circuit asym_butterfly_circuit = {
244         .name = "asym_butterfly",
245         .len = sizeof(asym_butterfly_tab)/sizeof(struct wp_coord),
246         .path = asym_butterfly_tab,
247 };
248
249 const struct wp_coord big_h_lambda_tab[] = {
250         { .i = 11, .j = 6, },
251         { .i = 10, .j = 6, },
252         { .i = 9, .j = 5, },
253         { .i = 8, .j = 5, },
254         { .i = 7, .j = 4, },
255         { .i = 6, .j = 4, },
256         { .i = 5, .j = 4, },
257         { .i = 4, .j = 5, },
258         { .i = 3, .j = 5, },
259         { .i = 2, .j = 6, },
260         { .i = 1, .j = 6, },
261         { .i = 1, .j = 5, },
262         { .i = 1, .j = 4, },
263         { .i = 1, .j = 3, },
264         { .i = 1, .j = 2, },
265         { .i = 1, .j = 1, },
266         { .i = 2, .j = 2, },
267         { .i = 3, .j = 2, },
268         { .i = 4, .j = 3, },
269         { .i = 5, .j = 3, },
270         { .i = 6, .j = 4, },
271         { .i = 7, .j = 4, },
272         { .i = 8, .j = 5, },
273         { .i = 9, .j = 5, },
274         { .i = 10, .j = 6, },
275         { .i = 11, .j = 6, },
276 };
277
278 const struct circuit big_h_lambda_circuit = {
279         .name = "big_h_lambda",
280         .len = sizeof(big_h_lambda_tab)/sizeof(struct wp_coord),
281         .path = big_h_lambda_tab,
282 };
283
284 const struct wp_coord letter_v_tab[] = {
285         { .i = 11, .j = 6, },
286         { .i = 10, .j = 6, },
287         { .i = 9, .j = 5, },
288         { .i = 8, .j = 5, },
289         { .i = 7, .j = 4, },
290         { .i = 6, .j = 4, },
291         { .i = 5, .j = 4, },
292         { .i = 4, .j = 5, },
293         { .i = 3, .j = 5, },
294         { .i = 2, .j = 6, },
295         { .i = 1, .j = 6, },
296         { .i = 1, .j = 5, },
297         { .i = 1, .j = 4, },
298         { .i = 2, .j = 4, },
299         { .i = 3, .j = 3, },
300         { .i = 4, .j = 3, },
301         { .i = 5, .j = 2, },
302         { .i = 6, .j = 2, },
303         { .i = 7, .j = 2, },
304         { .i = 8, .j = 3, },
305         { .i = 9, .j = 3, },
306         { .i = 10, .j = 4, },
307         { .i = 11, .j = 4, },
308         { .i = 11, .j = 5, },
309         { .i = 11, .j = 6, },
310 };
311
312 const struct circuit letter_v_circuit = {
313         .name = "letter_v",
314         .len = sizeof(letter_v_tab)/sizeof(struct wp_coord),
315         .path = letter_v_tab,
316 };
317
318 const struct wp_coord sperma_tab[] = {
319         { .i = 11, .j = 6, },
320         { .i = 10, .j = 6, },
321         { .i = 9, .j = 5, },
322         { .i = 8, .j = 5, },
323         { .i = 7, .j = 5, },
324         { .i = 6, .j = 6, },
325         { .i = 5, .j = 5, },
326         { .i = 4, .j = 5, },
327         { .i = 3, .j = 4, },
328         { .i = 2, .j = 4, },
329         { .i = 1, .j = 3, },
330         { .i = 1, .j = 4, },
331         { .i = 1, .j = 5, },
332         { .i = 1, .j = 6, },
333         { .i = 2, .j = 6, },
334         { .i = 3, .j = 5, },
335         { .i = 4, .j = 5, },
336         { .i = 5, .j = 5, },
337         { .i = 6, .j = 6, },
338         { .i = 7, .j = 5, },
339         { .i = 8, .j = 5, },
340         { .i = 9, .j = 5, },
341         { .i = 10, .j = 6, },
342         { .i = 11, .j = 6, },
343 };
344
345 const struct circuit sperma_circuit = {
346         .name = "sperma",
347         .len = sizeof(sperma_tab)/sizeof(struct wp_coord),
348         .path = sperma_tab,
349 };
350
351 /* list of all possible circuits */
352 const struct circuit *circuits[] = {
353         &butterfly_circuit,
354         &losange_circuit,
355         &triangle_circuit,
356         &answer_d_circuit,
357         &h_lambda_circuit,
358         &asym_butterfly_circuit,
359         &big_h_lambda_circuit,
360         &letter_v_circuit,
361         &sperma_circuit,
362         NULL,
363 };
364
365 /* symetric neighbor position */
366 static inline uint8_t opposite_position(uint8_t pos)
367 {
368         pos += 3;
369         if (pos > LINE_L_UP)
370                 pos -= 6;
371         return pos;
372 }
373
374 #ifdef HOST_VERSION
375 //#define TEST_STRAT_AVOID
376 #endif
377
378 #ifdef TEST_STRAT_AVOID
379 static uint8_t cc;
380 uint8_t xget_cob_count(void)
381 {
382         return cc;
383 }
384
385 static uint8_t bc;
386 uint8_t xget_ball_count(void)
387 {
388         return bc;
389 }
390
391 static uint32_t ts;
392 uint8_t xtime_get_s(void)
393 {
394         return ts;
395 }
396 #else
397 #define xget_cob_count() get_cob_count()
398 #define xget_ball_count() get_ball_count()
399 #define xtime_get_s() time_get_s()
400 #endif
401
402 /* return true if turn is at 60 deg */
403 uint8_t is_60deg(uint8_t dir1, uint8_t dir2)
404 {
405         int8_t turn;
406
407         turn = dir2-dir1;
408         if (turn < 0)
409                 turn += 6;
410         if (turn == 1)
411                 return 1;
412         if (turn == 5)
413                 return 1;
414         return 0;
415 }
416
417 /* return true if turn is at 60 deg */
418 uint8_t is_120deg(uint8_t dir1, uint8_t dir2)
419 {
420         int8_t turn;
421
422         turn = dir2-dir1;
423         if (turn < 0)
424                 turn += 6;
425         if (turn == 2)
426                 return 1;
427         if (turn == 4)
428                 return 1;
429         return 0;
430 }
431
432 /* get the neighbour of the point at specified dir, return -1 if
433  * there is no neighbor */
434 int8_t wp_get_neigh(uint8_t i, uint8_t j, uint8_t *ni, uint8_t *nj,
435                  uint8_t dir)
436 {
437         switch (dir) {
438         case LINE_UP:
439                 j++;
440                 break;
441         case LINE_R_UP:
442                 if ((i & 1)) j++;
443                 i++;
444                 break;
445         case LINE_R_DOWN:
446                 if (!(i & 1)) j--;
447                 i++;
448                 break;
449         case LINE_DOWN:
450                 j--;
451                 break;
452         case LINE_L_DOWN:
453                 if (!(i & 1)) j--;
454                 i--;
455                 break;
456         case LINE_L_UP:
457                 if ((i & 1)) j++;
458                 i--;
459                 break;
460         default:
461                 return -1;
462         }
463         if (i >= WAYPOINTS_NBX || j >= WAYPOINTS_NBY)
464                 return -1;
465
466         *ni = i;
467         *nj = j;
468         return 0;
469 }
470
471 static int8_t get_line_num(int8_t i, int8_t j, uint8_t dir)
472 {
473         uint8_t mod;
474
475         switch (dir) {
476         case LINE_UP:
477         case LINE_DOWN:
478                 if ((i & 1) == 0)
479                         return -1;
480                 return i/2;
481         case LINE_R_UP:
482         case LINE_L_DOWN:
483                 mod = i & 3;
484                 if ((mod == 0 || mod == 1) && ((j & 1) == 0))
485                         return -1;
486                 if ((mod == 2 || mod == 3) && ((j & 1) == 1))
487                         return -1;
488                 i &= 0xfe;
489                 j -= i/2;
490                 return (5-j)/2;
491         case LINE_R_DOWN:
492         case LINE_L_UP:
493                 mod = i & 3;
494                 if ((mod == 0 || mod == 3) && ((j & 1) == 0))
495                         return -1;
496                 if ((mod == 1 || mod == 2) && ((j & 1) == 1))
497                         return -1;
498                 i &= 0xfe;
499                 j += i/2;
500                 return (11-j)/2;
501         default:
502                 return -1;
503         }
504 }
505
506 static uint8_t get_dir(uint8_t prev_i, uint8_t prev_j,
507                        uint8_t i, uint8_t j)
508 {
509         int8_t diff_i, diff_j;
510
511         diff_i = i - prev_i;
512         diff_j = j - prev_j;
513
514         if (diff_i == 0 && diff_j == 1)
515                 return LINE_UP;
516         if (diff_i == 0 && diff_j == -1)
517                 return LINE_DOWN;
518
519         if ((prev_i & 1) == 0) {
520                 if (diff_i == 1 && diff_j == 0)
521                         return LINE_R_UP;
522                 if (diff_i == 1 && diff_j == -1)
523                         return LINE_R_DOWN;
524                 if (diff_i == -1 && diff_j == 0)
525                         return LINE_L_UP;
526                 if (diff_i == -1 && diff_j == -1)
527                         return LINE_L_DOWN;
528         }
529         else {
530                 if (diff_i == 1 && diff_j == 1)
531                         return LINE_R_UP;
532                 if (diff_i == 1 && diff_j == 0)
533                         return LINE_R_DOWN;
534                 if (diff_i == -1 && diff_j == 1)
535                         return LINE_L_UP;
536                 if (diff_i == -1 && diff_j == 0)
537                         return LINE_L_DOWN;
538         }
539
540         /* invalid value */
541         return 0xFF;
542 }
543
544 /* return approximative angle of line */
545 int16_t linedir2angle(uint8_t dir)
546 {
547         switch (dir) {
548         case LINE_UP:
549                 return COLOR_A(90);
550         case LINE_DOWN:
551                 return COLOR_A(-90);
552         case LINE_R_UP:
553                 return COLOR_A(30);
554         case LINE_R_DOWN:
555                 return COLOR_A(-90);
556         case LINE_L_UP:
557                 return COLOR_A(150);
558         case LINE_L_DOWN:
559                 return COLOR_A(-150);
560         default:
561                 return 0;
562         }
563 }
564
565 /* return true if a waypoint belongs to a line */
566 uint8_t wp_belongs_to_line(uint8_t i, uint8_t j, uint8_t linenum, uint8_t dir)
567 {
568         int8_t ln;
569         ln = get_line_num(i, j, dir);
570         if (ln == -1)
571                 return 0;
572         if (ln == linenum)
573                 return 1;
574         return 0;
575 }
576
577 /* count the number of non-black corns which are neighbors of
578  * specified cob */
579 uint8_t corn_count_neigh(uint8_t i, uint8_t j)
580 {
581         uint8_t dir, n = 0;
582         uint8_t ni, nj;
583
584         for (dir = LINE_UP; dir <= LINE_R_UP; dir++) {
585                 if (wp_get_neigh(i, j, &ni, &nj, dir) < 0)
586                         continue;
587
588                 /* is there a corn cob removed for more than 2 secs ? */
589                 if (strat_db.wp_table[ni][nj].type == WP_TYPE_CORN &&
590                     strat_db.wp_table[ni][nj].corn.color != I2C_COB_BLACK &&
591                     (strat_db.wp_table[ni][nj].present ||
592                      strat_db.wp_table[ni][nj].time_removed + 2 > time_get_s()))
593                         n ++;
594         }
595
596         return n;
597 }
598
599
600 /* fill circuit_wpline table with waypoints from circuit starting at
601  * i,j and using selected face */
602 static int8_t get_path(const struct circuit *circuit,
603                        uint8_t starti, uint8_t startj, uint8_t faceA,
604                        struct wp_line *circuit_wpline)
605 {
606         const struct wp_coord *curcircuit;
607         const struct wp_coord *start;
608         const struct wp_coord *end;
609         uint8_t prev_i, prev_j;
610         uint8_t dir, prev_dir = 0xFF;
611         uint8_t found = 0, i = 0, j = 0;
612         uint8_t linenum;
613         int8_t step = faceA ? 1 : -1;
614         int8_t path_len = 0;
615
616         /* start and end of circuit */
617         if (faceA) {
618                 start = &circuit->path[0];
619                 end = start + circuit->len - 1;
620         }
621         else {
622                 end = &circuit->path[0];
623                 start = end + circuit->len - 1;
624         }
625
626         DPR("%s(): %s face=%d\r\n", __FUNCTION__, circuit->name, faceA);
627
628         /* check that the point is present in the circuit */
629         for (curcircuit = start; curcircuit != end; curcircuit += step) {
630                 if (curcircuit->i == starti && curcircuit->j == startj) {
631                         found = 1;
632                         break;
633                 }
634         }
635         if (found == 0)
636                 return -1;
637
638
639         /* browse the circuit from starti, startj in the specified
640          * direction, and fill the table when direction changes */
641         prev_i = starti;
642         prev_j = startj;
643         for ( ; curcircuit != end;
644               curcircuit += step, prev_dir = dir, prev_i = i, prev_j = j) {
645
646                 i = curcircuit->i;
647                 j = curcircuit->j;
648
649                 dir = get_dir(prev_i, prev_j, i, j);
650
651                 if (prev_dir != dir) {
652                         linenum = get_line_num(prev_i, prev_j, dir);
653                         circuit_wpline[path_len].line_num = linenum;
654                         circuit_wpline[path_len].dir = dir;
655                         DPR("%s(): %d %d -> %d %d / len=%d num=%d dir=%d\r\n",
656                             __FUNCTION__, prev_i, prev_j, i, j, path_len, linenum, dir);
657                         path_len++;
658                 }
659         }
660
661         return path_len;
662 }
663
664 /* process score from retrieved objects number, and circuit len */
665 static int16_t get_score(uint32_t wcorn_retrieved,
666                          uint32_t ucorn_retrieved,
667                          uint16_t tomato_retrieved,
668                          uint16_t utomato_retrieved,
669                          uint8_t len, uint8_t opp_on_path)
670 {
671         int16_t score = 0;
672         uint8_t i;
673         uint32_t mask = 1;
674         uint8_t n;
675
676         /* score with corn */
677         n = xget_cob_count() * 2;
678         for (i = 0; i<CORN_NB; i++) {
679                 if (n >= 10)
680                         break;
681                 if (wcorn_retrieved & mask) {
682                         score += 250;
683                         n += 2;
684                 }
685                 if (n >= 10)
686                         break;
687                 if (ucorn_retrieved & mask) {
688                         score += 125;
689                         n += 1;
690                 }
691                 mask <<= 1UL;
692         }
693
694         DPR("get score: cob %d (->%d)\r\n", n, n/2);
695
696         /* score with tomato */
697         n = xget_ball_count();
698         mask = 1;
699         for (i = 0; i<TOMATO_NB; i++) {
700                 if (n >= 4)
701                         break;
702                 if (tomato_retrieved & mask) {
703                         score += 150;
704                         n += 1;
705                 }
706                 mask <<= 1UL;
707         }
708
709         DPR("get score: ball %d\r\n", n);
710
711         /* malus for long circuits */
712         score -= (len * 20);
713         DPR("malus for length: %d\r\n", len * 20);
714
715         /* double malus for long circuits if we don't have much
716          * time */
717 #define WP_SPEED 1
718         if (len * WP_SPEED > (MATCH_TIME - xtime_get_s())) {
719                 int32_t extra;
720                 extra = (len * WP_SPEED) - (MATCH_TIME - xtime_get_s());
721                 extra = (200 * extra);
722                 if (extra < 0) /* should not happen */
723                         extra = 0;
724                 if (extra > 10000)
725                         extra = 10000;
726                 score -= extra;
727                 DPR("malus for length + time: %d\r\n", extra);
728         }
729
730         /* malus if there is opponent on the path */
731         if (opp_on_path) {
732                 DPR("malus for opponent: %d\r\n", (500 * opp_on_path));
733                 score -= (500 * opp_on_path);
734         }
735
736         return score;
737 }
738
739 /* return the corn type of specified coords: I2C_COB_WHITE,
740  * I2C_COB_UNKNOWN, or I2C_COB_NONE if it is black or not present */
741 static uint8_t get_corn_type(uint8_t i, uint8_t j)
742 {
743         uint8_t color;
744         /* is there a corn cob ? */
745         if (strat_db.wp_table[i][j].type == WP_TYPE_CORN &&
746             strat_db.wp_table[i][j].present) {
747                 color = strat_db.wp_table[i][j].corn.color;
748                 if (color == I2C_COB_WHITE)
749                         return I2C_COB_WHITE;
750                 else if (color == I2C_COB_UNKNOWN)
751                         return I2C_COB_UNKNOWN;
752         }
753         return I2C_COB_NONE;
754 }
755
756 /* i,j: starting position */
757 static int8_t evaluate_one_face(const struct circuit *circuit,
758                                 uint8_t starti, uint8_t startj,
759                                 uint8_t faceA, int16_t *score)
760 {
761         const struct wp_coord *curcircuit;
762         const struct wp_coord *start;
763         const struct wp_coord *end;
764         uint32_t wcorn_retrieved = 0; /* bit mask */
765         uint32_t ucorn_retrieved = 0; /* bit mask */
766         uint16_t tomato_retrieved = 0; /* bit mask */
767         uint16_t utomato_retrieved = 0; /* bit mask */
768         uint8_t opponent_on_path = 0;
769         uint8_t len = 0, found = 0;
770         uint8_t i, j, prev_i, prev_j;
771         uint8_t ni = 0, nj = 0;
772         uint8_t dir, color, idx, visited;
773         int8_t step = faceA ? 1 : -1;
774         int16_t x, y;
775         int32_t d, prev_d = 0;
776         int16_t oppx, oppy;
777
778         *score = 0x8000; /* -int_max */
779
780         /* start and end of circuit */
781         if (faceA) {
782                 start = &circuit->path[0];
783                 end = start + circuit->len - 1;
784         }
785         else {
786                 end = &circuit->path[0];
787                 start = end + circuit->len - 1;
788         }
789
790         DPR("%s() face: %s %d\r\n", __FUNCTION__, circuit->name, faceA);
791
792         /* check that the point is present in the circuit */
793         for (curcircuit = start; curcircuit != end; curcircuit += step) {
794                 if (curcircuit->i == starti && curcircuit->j == startj) {
795                         found = 1;
796                         break;
797                 }
798         }
799         if (found == 0)
800                 return -1;
801
802         /* get opponent coords */
803         if (get_opponent_xy(&oppx, &oppy) < 0)
804                 oppx = I2C_OPPONENT_NOT_THERE;
805         else
806                 DPR("%s() opponent: %d, %d\r\n", __FUNCTION__, oppx, oppy);
807
808         /* silent the compiler */
809         prev_i = 0xff;
810         prev_j = 0xff;
811
812         /* browse all points and calculate the score */
813         for (; /* start at starti,startj */
814              curcircuit != end;
815              curcircuit += step, len ++, prev_i = i, prev_j = j) {
816                 i = curcircuit->i;
817                 j = curcircuit->j;
818
819                 /* is opponent near the point ? */
820                 ijcoord_to_xycoord(i, j, &x, &y);
821                 if (oppx != I2C_OPPONENT_NOT_THERE) {
822                         d = quad_distance_between(oppx, oppy, x, y);
823                         DPR("%s(): opp at %d mm (ij=%d,%d opp=%d,%d pos=%d,%d)\r\n",
824                             __FUNCTION__, d, i, j, oppx, oppy, x, y);
825                         if (d < (250L*250L) && d < prev_d)
826                                 opponent_on_path += 3;
827                         else if (d < (500L*500L) && d < prev_d)
828                                 opponent_on_path ++;
829                         prev_d = d;
830                 }
831
832                 /* don't try to look cobs/tomato for first point */
833                 if (curcircuit == start)
834                         continue;
835
836                 /* get current direction, we wil check cobs behind us
837                  * on left and right */
838                 dir = get_dir(prev_i, prev_j, i, j);
839
840                 DPR("%d %d -> %d %d  (%d)\n", prev_i, prev_j, i, j, dir);
841
842                 /* is there a tomato ? */
843                 if (strat_db.wp_table[i][j].type == WP_TYPE_TOMATO &&
844                     strat_db.wp_table[i][j].present) {
845                         if (strat_db.wp_table[i][j].opp_visited) {
846                                 DPR("  TOMATO (opp visited)\n");
847                                 utomato_retrieved |= (1UL << strat_db.wp_table[i][j].tomato.idx);
848                         }
849                         else {
850                                 DPR("  TOMATO\n");
851                                 tomato_retrieved |= (1UL << strat_db.wp_table[i][j].tomato.idx);
852                         }
853                 }
854
855                 /* behind left */
856                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 2) % 6) == 0) {
857                         color = get_corn_type(ni, nj);
858                         idx = strat_db.wp_table[ni][nj].corn.idx;
859                         visited = strat_db.wp_table[ni][nj].opp_visited;
860                         if (color == I2C_COB_WHITE && !visited) {
861                                 DPR("  LEFT WCORN (%d)\n", idx);
862                                 wcorn_retrieved |= (1UL << idx);
863                         }
864                         else if (color == I2C_COB_WHITE && visited) {
865                                 DPR("  LEFT CORN visited (%d)\n", idx);
866                                 ucorn_retrieved |= (1UL << idx);
867                         }
868                         else if (color == I2C_COB_UNKNOWN) {
869                                 DPR("  LEFT UCORN (%d)\n", idx);
870                                 ucorn_retrieved |= (1UL << idx);
871                         }
872                 }
873
874                 /* behind right */
875                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 4) % 6) == 0) {
876                         color = get_corn_type(ni, nj);
877                         idx = strat_db.wp_table[ni][nj].corn.idx;
878                         visited = strat_db.wp_table[ni][nj].opp_visited;
879                         if (color == I2C_COB_WHITE && !visited) {
880                                 DPR("  RIGHT WCORN (%d)\n", idx);
881                                 wcorn_retrieved |= (1UL << idx);
882                         }
883                         else if (color == I2C_COB_WHITE && visited) {
884                                 DPR("  RIGHT CORN visited (%d)\n", idx);
885                                 ucorn_retrieved |= (1UL << idx);
886                         }
887                         else if (color == I2C_COB_UNKNOWN) {
888                                 DPR("  RIGHT UCORN (%d)\n", idx);
889                                 ucorn_retrieved |= (1UL << idx);
890                         }
891                 }
892
893                 /* prev_i, prev_j, len and curcircuit are updated in
894                  * for (;;) */
895         }
896
897         /* write score and exit */
898         *score = get_score(wcorn_retrieved, ucorn_retrieved,
899                            tomato_retrieved, utomato_retrieved,
900                            len, opponent_on_path);
901         return 0;
902 }
903
904 /* i,j: starting position */
905 static int8_t evaluate_one_circuit(const struct circuit *circuit,
906                                    uint8_t starti, uint8_t startj,
907                                    int16_t *scoreA, int16_t *scoreB)
908 {
909         if (evaluate_one_face(circuit, starti, startj, 1, scoreA) < 0)
910                 return -1;
911
912         /* we are on eject point, scoreB is the same */
913         if (starti == 11 && startj == 6) {
914                 *scoreB = *scoreA;
915                 return 0;
916         }
917
918         if (evaluate_one_face(circuit, starti, startj, 0, scoreB) < 0)
919                 return -1;
920         return 0;
921 }
922
923 /* i,j starting position */
924 static int8_t find_best_circuit(uint8_t i, uint8_t j,
925                                 const struct circuit **selected_circuit,
926                                 int8_t *selected_face)
927 {
928         const struct circuit **circuit;
929         int16_t scoreA, scoreB;
930         int16_t selected_score = 0x8000; /* ~-int_max */
931         int8_t found = -1;
932
933         *selected_face = 0;
934         *selected_circuit = circuits[0] ;
935         for (circuit = &circuits[0]; *circuit; circuit++) {
936                 if (evaluate_one_circuit(*circuit, i, j, &scoreA, &scoreB) < 0)
937                         continue;
938                 found = 0;
939                 DEBUG(E_USER_STRAT, "Scores for %s are: faceA=%d, faceB=%d",
940                       (*circuit)->name, scoreA, scoreB);
941                 if (scoreA > selected_score) {
942                         *selected_circuit = *circuit;
943                         selected_score = scoreA;
944                         *selected_face = 1;
945                 }
946                 if (scoreB > selected_score) {
947                         *selected_circuit = *circuit;
948                         selected_score = scoreB;
949                         *selected_face = 0;
950                 }
951         }
952
953         if (found == -1)
954                 DEBUG(E_USER_STRAT, "no circuit found");
955         else
956                 DEBUG(E_USER_STRAT, "circuit found: %s, %s",
957                       (*selected_circuit)->name,
958                       (*selected_face) ? "faceA":"faceB");
959         return found;
960 }
961
962 static void init_all_circuits(void)
963 {
964         const struct circuit **circuit;
965         const struct wp_coord *cur;
966         const struct wp_coord *start;
967         const struct wp_coord *end;
968         uint8_t prev_i, prev_j, i, j, dir;
969
970         for (circuit = &circuits[0]; *circuit; circuit++) {
971                 start = &(*circuit)->path[0];
972                 end = start + (*circuit)->len - 1;
973
974                 prev_i = start->i;
975                 prev_j = start->j;
976                 start ++;
977
978                 for (cur = start; cur != end;
979                      cur ++, prev_i = i, prev_j = j) {
980
981                         i = cur->i;
982                         j = cur->j;
983
984                         strat_db.wp_table[i][j].on_circuit = 1;
985
986                         dir = get_dir(prev_i, prev_j, i, j);
987                         if (dir == 0xFF)
988                                 printf_P("Bad circuit %s %d %d\r\n", (*circuit)->name, i, j);
989                 }
990         }
991 }
992
993
994 static void dump_circuit_wp(struct wp_line *circuit_wpline, int8_t len)
995 {
996         int8_t i;
997         if (len <= 0)
998                 return;
999         for (i = 0; i < len; i ++) {
1000                 DEBUG(E_USER_STRAT, "linenum %d dir %d",
1001                       circuit_wpline[i].line_num,
1002                        circuit_wpline[i].dir);
1003         }
1004
1005 }
1006
1007 /* choose a circuit, then harvest on this circuit */
1008 uint8_t strat_harvest_circuit(void)
1009 {
1010         const struct circuit *selected_circuit;
1011         int8_t selected_face;
1012         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
1013         int8_t len;
1014         uint8_t i, j, idx;
1015         int16_t x, y;
1016         uint8_t linenum, prev_linenum;
1017         uint8_t dir, prev_dir;
1018         uint8_t err;
1019
1020         strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
1021         strat_want_pack = 1;
1022
1023         x = position_get_x_s16(&mainboard.pos);
1024         y = position_get_y_s16(&mainboard.pos);
1025
1026         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0) {
1027                 DEBUG(E_USER_STRAT, "%s(): cannot find waypoint at %d,%d",
1028                       __FUNCTION__, x, y);
1029                 err = END_ERROR;
1030                 goto fail;
1031         }
1032
1033         if (find_best_circuit(i, j, &selected_circuit, &selected_face) < 0) {
1034                 DEBUG(E_USER_STRAT, "%s(): cannot find a good circuit",
1035                       __FUNCTION__);
1036                 err = END_ERROR;
1037                 goto fail;
1038         }
1039
1040         len = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1041         if (len < 0) {
1042                 DEBUG(E_USER_STRAT, "%s(): cannot find a path",
1043                       __FUNCTION__);
1044                 err = END_ERROR;
1045                 goto fail;
1046         }
1047
1048         dump_circuit_wp(circuit_wpline, len);
1049
1050         prev_linenum = circuit_wpline[0].line_num;
1051         prev_dir = circuit_wpline[0].dir;
1052
1053         /* fix orientation first */
1054         trajectory_a_abs(&mainboard.traj, linedir2angle(prev_dir));
1055         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1056         if (!TRAJ_SUCCESS(err))
1057                 goto fail;
1058
1059         strat_want_pack = 0;
1060
1061         /* do all lines of circuit */
1062         for (idx = 1; idx < len; idx ++) {
1063         retry:
1064                 linenum = circuit_wpline[idx].line_num;
1065                 dir = circuit_wpline[idx].dir;
1066
1067                 DEBUG(E_USER_STRAT, "%s(): line %d dir %d -> line %d dir %d",
1068                       __FUNCTION__, prev_linenum, prev_dir, linenum, dir);
1069                 err = line2line(prev_linenum, prev_dir, linenum, dir,
1070                                 TRAJ_FLAGS_NO_NEAR);
1071
1072                 /* in some cases it is better to wait that obstacle is
1073                  * gone before starting to avoid it */
1074                 if (err == END_OBSTACLE &&
1075                     strat_conf.flags & STRAT_CONF_WAIT_OBSTACLE &&
1076                     time_get_s() > strat_conf.prev_wait_obstacle + 5) {
1077                         strat_conf.prev_wait_obstacle = time_get_s();
1078                         time_wait_ms(2000);
1079                         goto retry;
1080                 }
1081                 if (!TRAJ_SUCCESS(err))
1082                         goto fail;
1083
1084                 prev_linenum = linenum;
1085                 prev_dir = dir;
1086         }
1087         err = END_TRAJ;
1088
1089  fail:
1090         strat_want_pack = 0;
1091         return err;
1092 }
1093
1094 /* list of waypoints when we are not on a circuit */
1095 const struct xy_point unblock_pts[] = {
1096         { .x = 375, .y = 597 },  /* 1,1 */
1097         { .x = 2625, .y = 597 }, /* 11,1 */
1098         { .x = 1500, .y = 722 }, /* 6,2 */
1099         { .x = 375, .y = 1097 }, /* 1,3 */
1100         { .x = 375, .y = 1597 }, /* 1,5 */
1101         { .x = 2625, .y = 1097 }, /* 11,3 */
1102         { .x = 2625, .y = 1597 }, /* 11,5 */
1103         { .x = 1500, .y = 1722 }, /* 6,6 */
1104 };
1105
1106
1107 /* try to unblock in any situation */
1108 uint8_t strat_unblock(void)
1109 {
1110         int16_t x, y, posx, posy;
1111         uint8_t i, j, k;
1112         uint16_t old_dspeed, old_aspeed;
1113         uint8_t err;
1114         uint16_t d_min = 0x7FFF, d;
1115         const struct xy_point *pt;
1116
1117         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
1118
1119         strat_want_pack = 1;
1120         strat_get_speed(&old_dspeed, &old_aspeed);
1121
1122         strat_hardstop();
1123         strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
1124         posx = position_get_x_s16(&mainboard.pos);
1125         posy = position_get_y_s16(&mainboard.pos);
1126         x = posx;
1127         y = posy;
1128
1129         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0)
1130                 x = -1;
1131         else if (strat_db.wp_table[i][j].on_circuit == 0)
1132                 x = -1;
1133
1134         /* find the nearest unblock point */
1135         if (x == -1) {
1136
1137                 /* browse all points and find the nearest */
1138                 for (k = 0; k < sizeof(unblock_pts)/sizeof(*unblock_pts); k++) {
1139                         pt = &unblock_pts[k];
1140                         d = distance_between(posx, posy, pt->x, COLOR_Y(pt->y));
1141                         if (d < d_min) {
1142                                 d_min = d;
1143                                 x = pt->x;
1144                                 y = COLOR_Y(pt->y);
1145                         }
1146                 }
1147         }
1148         DEBUG(E_USER_STRAT, "%s() unblock point is %d,%d",
1149               __FUNCTION__, x, y);
1150
1151         /* XXX if opponent is too close, go back, or wait ? */
1152
1153         /* go to nearest waypoint */
1154         trajectory_goto_xy_abs(&mainboard.traj, x, y);
1155         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1156         if (err == END_TIMER)
1157                 return err;
1158
1159         if (!TRAJ_SUCCESS(err))
1160                 return err;
1161
1162         strat_set_speed(old_dspeed, old_aspeed);
1163         return END_TRAJ;
1164 }
1165
1166 void strat_avoid_init(void)
1167 {
1168         init_all_circuits();
1169
1170 #ifdef TEST_STRAT_AVOID
1171         uint8_t i, j;
1172         const struct circuit *selected_circuit;
1173         int8_t selected_face;
1174         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
1175         int8_t ret;
1176
1177         i = 1; j = 1;
1178         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1179
1180         ts = 0; bc = 0; cc = 0;
1181         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1182         find_best_circuit(i, j, &selected_circuit, &selected_face);
1183         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1184         dump_circuit_wp(circuit_wpline, ret);
1185
1186         ts = 0; bc = 3; cc = 0;
1187         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1188         find_best_circuit(i, j, &selected_circuit, &selected_face);
1189         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1190         dump_circuit_wp(circuit_wpline, ret);
1191
1192         ts = 0; bc = 4; cc = 0;
1193         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1194         find_best_circuit(i, j, &selected_circuit, &selected_face);
1195         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1196         dump_circuit_wp(circuit_wpline, ret);
1197
1198         ts = 0; bc = 3; cc = 5;
1199         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1200         find_best_circuit(i, j, &selected_circuit, &selected_face);
1201         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1202         dump_circuit_wp(circuit_wpline, ret);
1203
1204         ts = 0; bc = 4; cc = 5;
1205         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1206         find_best_circuit(i, j, &selected_circuit, &selected_face);
1207         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1208         dump_circuit_wp(circuit_wpline, ret);
1209
1210         ts = 80; bc = 0; cc = 0;
1211         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1212         find_best_circuit(i, j, &selected_circuit, &selected_face);
1213         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1214         dump_circuit_wp(circuit_wpline, ret);
1215
1216         i = 4; j = 3;
1217         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1218
1219         ts = 0; bc = 0; cc = 0;
1220         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1221         find_best_circuit(i, j, &selected_circuit, &selected_face);
1222         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1223         dump_circuit_wp(circuit_wpline, ret);
1224
1225         ts = 0; bc = 3; cc = 0;
1226         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1227         find_best_circuit(i, j, &selected_circuit, &selected_face);
1228         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1229         dump_circuit_wp(circuit_wpline, ret);
1230
1231         ts = 80; bc = 0; cc = 0;
1232         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1233         find_best_circuit(i, j, &selected_circuit, &selected_face);
1234         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1235         dump_circuit_wp(circuit_wpline, ret);
1236
1237         i = 11; j = 6;
1238         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1239
1240         ts = 0; bc = 0; cc = 0;
1241         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1242         find_best_circuit(i, j, &selected_circuit, &selected_face);
1243         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1244         dump_circuit_wp(circuit_wpline, ret);
1245
1246         ts = 0; bc = 3; cc = 0;
1247         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1248         find_best_circuit(i, j, &selected_circuit, &selected_face);
1249         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1250         dump_circuit_wp(circuit_wpline, ret);
1251
1252         ts = 80; bc = 0; cc = 0;
1253         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1254         find_best_circuit(i, j, &selected_circuit, &selected_face);
1255         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1256         dump_circuit_wp(circuit_wpline, ret);
1257 #endif
1258 }