2658b46ed31bbb44bf0739c1cb5f68df4f062f7c
[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                          uint8_t len, uint8_t opp_on_path)
669 {
670         int16_t score = 0;
671         uint8_t i;
672         uint32_t mask = 1;
673         uint8_t n;
674
675         /* score with corn */
676         n = xget_cob_count() * 2;
677         for (i = 0; i<CORN_NB; i++) {
678                 if (n >= 10)
679                         break;
680                 if (wcorn_retrieved & mask) {
681                         score += 250;
682                         n += 2;
683                 }
684                 if (n >= 10)
685                         break;
686                 if (ucorn_retrieved & mask) {
687                         score += 125;
688                         n += 1;
689                 }
690                 mask <<= 1UL;
691         }
692
693         DPR("get score: cob %d (->%d)\r\n", n, n/2);
694
695         /* score with tomato */
696         n = xget_ball_count();
697         mask = 1;
698         for (i = 0; i<TOMATO_NB; i++) {
699                 if (n >= 4)
700                         break;
701                 if (tomato_retrieved & mask) {
702                         score += 150;
703                         n += 1;
704                 }
705                 mask <<= 1UL;
706         }
707
708         DPR("get score: ball %d\r\n", n);
709
710         /* malus for long circuits */
711         score -= (len * 20);
712         DPR("malus for length: %d\r\n", len * 20);
713
714         /* double malus for long circuits if we don't have much
715          * time */
716 #define WP_SPEED 1
717         if (len * WP_SPEED > (MATCH_TIME - xtime_get_s())) {
718                 int32_t extra;
719                 extra = (len * WP_SPEED) - (MATCH_TIME - xtime_get_s());
720                 extra = (200 * extra);
721                 if (extra < 0) /* should not happen */
722                         extra = 0;
723                 if (extra > 10000)
724                         extra = 10000;
725                 score -= extra;
726                 DPR("malus for length + time: %d\r\n", extra);
727         }
728
729         /* malus if there is opponent on the path */
730         if (opp_on_path) {
731                 DPR("malus for opponent: %d\r\n", (500 * opp_on_path));
732                 score -= (500 * opp_on_path);
733         }
734
735         return score;
736 }
737
738 /* return the corn type of specified coords: I2C_COB_WHITE,
739  * I2C_COB_UNKNOWN, or I2C_COB_NONE if it is black or not present */
740 static uint8_t get_corn_type(uint8_t i, uint8_t j)
741 {
742         uint8_t color;
743         /* is there a corn cob ? */
744         if (strat_db.wp_table[i][j].type == WP_TYPE_CORN &&
745             strat_db.wp_table[i][j].present) {
746                 color = strat_db.wp_table[i][j].corn.color;
747                 if (color == I2C_COB_WHITE)
748                         return I2C_COB_WHITE;
749                 else if (color == I2C_COB_UNKNOWN)
750                         return I2C_COB_UNKNOWN;
751         }
752         return I2C_COB_NONE;
753 }
754
755 /* i,j: starting position */
756 static int8_t evaluate_one_face(const struct circuit *circuit,
757                                 uint8_t starti, uint8_t startj,
758                                 uint8_t faceA, int16_t *score)
759 {
760         const struct wp_coord *curcircuit;
761         const struct wp_coord *start;
762         const struct wp_coord *end;
763         uint32_t wcorn_retrieved = 0; /* bit mask */
764         uint32_t ucorn_retrieved = 0; /* bit mask */
765         uint16_t tomato_retrieved = 0; /* bit mask */
766         uint8_t opponent_on_path = 0;
767         uint8_t len = 0, found = 0;
768         uint8_t i, j, prev_i, prev_j;
769         uint8_t ni = 0, nj = 0;
770         uint8_t dir, color, idx;
771         int8_t step = faceA ? 1 : -1;
772         int16_t x, y;
773         int32_t d, prev_d = 0;
774         int16_t oppx, oppy;
775
776         *score = 0x8000; /* -int_max */
777
778         /* start and end of circuit */
779         if (faceA) {
780                 start = &circuit->path[0];
781                 end = start + circuit->len - 1;
782         }
783         else {
784                 end = &circuit->path[0];
785                 start = end + circuit->len - 1;
786         }
787
788         DPR("%s() face: %s %d\r\n", __FUNCTION__, circuit->name, faceA);
789
790         /* check that the point is present in the circuit */
791         for (curcircuit = start; curcircuit != end; curcircuit += step) {
792                 if (curcircuit->i == starti && curcircuit->j == startj) {
793                         found = 1;
794                         break;
795                 }
796         }
797         if (found == 0)
798                 return -1;
799
800         /* get opponent coords */
801         if (get_opponent_xy(&oppx, &oppy) < 0)
802                 oppx = I2C_OPPONENT_NOT_THERE;
803         else
804                 DPR("%s() opponent: %d, %d\r\n", __FUNCTION__, oppx, oppy);
805
806         /* silent the compiler */
807         prev_i = 0xff;
808         prev_j = 0xff;
809
810         /* browse all points and calculate the score */
811         for (; /* start at starti,startj */
812              curcircuit != end;
813              curcircuit += step, len ++, prev_i = i, prev_j = j) {
814                 i = curcircuit->i;
815                 j = curcircuit->j;
816
817                 /* is opponent near the point ? */
818                 ijcoord_to_xycoord(i, j, &x, &y);
819                 if (oppx != I2C_OPPONENT_NOT_THERE) {
820                         d = quad_distance_between(oppx, oppy, x, y);
821                         DPR("%s(): opp at %d mm (ij=%d,%d opp=%d,%d pos=%d,%d)\r\n",
822                             __FUNCTION__, d, i, j, oppx, oppy, x, y);
823                         if (d < (250L*250L) && d < prev_d)
824                                 opponent_on_path += 3;
825                         else if (d < (500L*500L) && d < prev_d)
826                                 opponent_on_path ++;
827                         prev_d = d;
828                 }
829
830                 /* don't try to look cobs/tomato for first point */
831                 if (curcircuit == start)
832                         continue;
833
834                 /* get current direction, we wil check cobs behind us
835                  * on left and right */
836                 dir = get_dir(prev_i, prev_j, i, j);
837
838                 DPR("%d %d -> %d %d  (%d)\n", prev_i, prev_j, i, j, dir);
839
840                 /* is there a tomato ? */
841                 if (strat_db.wp_table[i][j].type == WP_TYPE_TOMATO &&
842                     strat_db.wp_table[i][j].present) {
843                         DPR("  TOMATO\n");
844                         tomato_retrieved |= (1UL << strat_db.wp_table[i][j].tomato.idx);
845                 }
846
847                 /* behind left */
848                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 2) % 6) == 0) {
849                         color = get_corn_type(ni, nj);
850                         idx = strat_db.wp_table[ni][nj].corn.idx;
851                         if (color == I2C_COB_WHITE) {
852                                 DPR("  LEFT WCORN (%d)\n", idx);
853                                 wcorn_retrieved |= (1UL << idx);
854                         }
855                         else if (color == I2C_COB_UNKNOWN) {
856                                 DPR("  LEFT UCORN (%d)\n", idx);
857                                 ucorn_retrieved |= (1UL << idx);
858                         }
859                 }
860
861                 /* behind right */
862                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 4) % 6) == 0) {
863                         color = get_corn_type(ni, nj);
864                         idx = strat_db.wp_table[ni][nj].corn.idx;
865                         if (color == I2C_COB_WHITE) {
866                                 DPR("  RIGHT WCORN (%d)\n", idx);
867                                 wcorn_retrieved |= (1UL << idx);
868                         }
869                         else if (color == I2C_COB_UNKNOWN) {
870                                 DPR("  RIGHT UCORN (%d)\n", idx);
871                                 ucorn_retrieved |= (1UL << idx);
872                         }
873                 }
874
875                 /* prev_i, prev_j, len and curcircuit are updated in
876                  * for (;;) */
877         }
878
879         /* write score and exit */
880         *score = get_score(wcorn_retrieved, ucorn_retrieved,
881                            tomato_retrieved, len, opponent_on_path);
882         return 0;
883 }
884
885 /* i,j: starting position */
886 static int8_t evaluate_one_circuit(const struct circuit *circuit,
887                                    uint8_t starti, uint8_t startj,
888                                    int16_t *scoreA, int16_t *scoreB)
889 {
890         if (evaluate_one_face(circuit, starti, startj, 1, scoreA) < 0)
891                 return -1;
892
893         /* we are on eject point, scoreB is the same */
894         if (starti == 11 && startj == 6) {
895                 *scoreB = *scoreA;
896                 return 0;
897         }
898
899         if (evaluate_one_face(circuit, starti, startj, 0, scoreB) < 0)
900                 return -1;
901         return 0;
902 }
903
904 /* i,j starting position */
905 static int8_t find_best_circuit(uint8_t i, uint8_t j,
906                                 const struct circuit **selected_circuit,
907                                 int8_t *selected_face)
908 {
909         const struct circuit **circuit;
910         int16_t scoreA, scoreB;
911         int16_t selected_score = 0x8000; /* ~-int_max */
912         int8_t found = -1;
913
914         *selected_face = 0;
915         *selected_circuit = circuits[0] ;
916         for (circuit = &circuits[0]; *circuit; circuit++) {
917                 if (evaluate_one_circuit(*circuit, i, j, &scoreA, &scoreB) < 0)
918                         continue;
919                 found = 0;
920                 DEBUG(E_USER_STRAT, "Scores for %s are: faceA=%d, faceB=%d",
921                       (*circuit)->name, scoreA, scoreB);
922                 if (scoreA > selected_score) {
923                         *selected_circuit = *circuit;
924                         selected_score = scoreA;
925                         *selected_face = 1;
926                 }
927                 if (scoreB > selected_score) {
928                         *selected_circuit = *circuit;
929                         selected_score = scoreB;
930                         *selected_face = 0;
931                 }
932         }
933
934         if (found == -1)
935                 DEBUG(E_USER_STRAT, "no circuit found");
936         else
937                 DEBUG(E_USER_STRAT, "circuit found: %s, %s",
938                       (*selected_circuit)->name,
939                       (*selected_face) ? "faceA":"faceB");
940         return found;
941 }
942
943 static void init_all_circuits(void)
944 {
945         const struct circuit **circuit;
946         const struct wp_coord *cur;
947         const struct wp_coord *start;
948         const struct wp_coord *end;
949         uint8_t prev_i, prev_j, i, j, dir;
950
951         for (circuit = &circuits[0]; *circuit; circuit++) {
952                 start = &(*circuit)->path[0];
953                 end = start + (*circuit)->len - 1;
954
955                 prev_i = start->i;
956                 prev_j = start->j;
957                 start ++;
958
959                 for (cur = start; cur != end;
960                      cur ++, prev_i = i, prev_j = j) {
961
962                         i = cur->i;
963                         j = cur->j;
964
965                         strat_db.wp_table[i][j].on_circuit = 1;
966
967                         dir = get_dir(prev_i, prev_j, i, j);
968                         if (dir == 0xFF)
969                                 printf_P("Bad circuit %s %d %d\r\n", (*circuit)->name, i, j);
970                 }
971         }
972 }
973
974
975 static void dump_circuit_wp(struct wp_line *circuit_wpline, int8_t len)
976 {
977         int8_t i;
978         if (len <= 0)
979                 return;
980         for (i = 0; i < len; i ++) {
981                 DEBUG(E_USER_STRAT, "linenum %d dir %d",
982                       circuit_wpline[i].line_num,
983                        circuit_wpline[i].dir);
984         }
985
986 }
987
988 /* choose a circuit, then harvest on this circuit */
989 uint8_t strat_harvest_circuit(void)
990 {
991         const struct circuit *selected_circuit;
992         int8_t selected_face;
993         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
994         int8_t len;
995         uint8_t i, j, idx;
996         int16_t x, y;
997         uint8_t linenum, prev_linenum;
998         uint8_t dir, prev_dir;
999         uint8_t err;
1000
1001         strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
1002         strat_want_pack = 1;
1003
1004         printf("PACK PACK\n");
1005
1006         x = position_get_x_s16(&mainboard.pos);
1007         y = position_get_y_s16(&mainboard.pos);
1008
1009         if (xycoord_to_ijcoord(&x, &y, &i, &j) < 0) {
1010                 DEBUG(E_USER_STRAT, "%s(): cannot find waypoint at %d,%d",
1011                       __FUNCTION__, x, y);
1012                 err = END_ERROR;
1013                 goto fail;
1014         }
1015
1016         if (find_best_circuit(i, j, &selected_circuit, &selected_face) < 0) {
1017                 DEBUG(E_USER_STRAT, "%s(): cannot find a good circuit",
1018                       __FUNCTION__);
1019                 err = END_ERROR;
1020                 goto fail;
1021         }
1022
1023         len = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1024         if (len < 0) {
1025                 DEBUG(E_USER_STRAT, "%s(): cannot find a path",
1026                       __FUNCTION__);
1027                 err = END_ERROR;
1028                 goto fail;
1029         }
1030
1031         dump_circuit_wp(circuit_wpline, len);
1032
1033         prev_linenum = circuit_wpline[0].line_num;
1034         prev_dir = circuit_wpline[0].dir;
1035
1036         /* fix orientation first */
1037         trajectory_a_abs(&mainboard.traj, linedir2angle(prev_dir));
1038         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1039         if (!TRAJ_SUCCESS(err))
1040                 goto fail;
1041
1042         strat_want_pack = 0;
1043         printf("UNPACK UNPACK\n");
1044
1045         /* do all lines of circuit */
1046         for (idx = 1; idx < len; idx ++) {
1047                 linenum = circuit_wpline[idx].line_num;
1048                 dir = circuit_wpline[idx].dir;
1049
1050                 DEBUG(E_USER_STRAT, "%s(): line %d dir %d -> line %d dir %d",
1051                       __FUNCTION__, prev_linenum, prev_dir, linenum, dir);
1052                 err = line2line(prev_linenum, prev_dir, linenum, dir,
1053                                 TRAJ_FLAGS_NO_NEAR);
1054                 if (!TRAJ_SUCCESS(err))
1055                         goto fail;
1056
1057                 prev_linenum = linenum;
1058                 prev_dir = dir;
1059         }
1060         err = END_TRAJ;
1061
1062  fail:
1063         strat_want_pack = 0;
1064         return err;
1065 }
1066
1067 /* list of waypoints when we are not on a circuit */
1068 const struct xy_point unblock_pts[] = {
1069         { .x = 375, .y = 597 },  /* 1,1 */
1070         { .x = 2625, .y = 597 }, /* 11,1 */
1071         { .x = 1500, .y = 722 }, /* 6,2 */
1072         { .x = 375, .y = 1097 }, /* 1,3 */
1073         { .x = 375, .y = 1597 }, /* 1,5 */
1074         { .x = 2625, .y = 1097 }, /* 11,3 */
1075         { .x = 2625, .y = 1597 }, /* 11,5 */
1076         { .x = 1500, .y = 1722 }, /* 6,6 */
1077 };
1078
1079
1080 /* try to unblock in any situation */
1081 uint8_t strat_unblock(void)
1082 {
1083         int16_t x, y;
1084         uint8_t i, j, k;
1085         uint16_t old_dspeed, old_aspeed;
1086         uint8_t err;
1087         uint16_t d_min = 0xFFFF, d;
1088         const struct xy_point *pt;
1089
1090         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
1091
1092         strat_want_pack = 1;
1093         strat_get_speed(&old_dspeed, &old_aspeed);
1094
1095         strat_hardstop();
1096         strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
1097         x = position_get_x_s16(&mainboard.pos);
1098         y = position_get_y_s16(&mainboard.pos);
1099
1100         if (xycoord_to_ijcoord(&x, &y, &i, &j) < 0)
1101                 x = -1;
1102         else if (strat_db.wp_table[i][j].on_circuit == 0)
1103                 x = -1;
1104
1105         /* find the nearest unblock point */
1106         if (x == -1) {
1107                 /* position may have been modified */
1108                 x = position_get_x_s16(&mainboard.pos);
1109                 y = position_get_y_s16(&mainboard.pos);
1110
1111                 /* browse all points and find the nearest */
1112                 for (k = 0; k < sizeof(unblock_pts)/sizeof(*unblock_pts); k++) {
1113                         pt = &unblock_pts[k];
1114                         d = distance_between(x, y, pt->x, COLOR_Y(pt->y));
1115                         if (d < d_min) {
1116                                 d_min = d;
1117                                 x = pt->x;
1118                                 y = COLOR_Y(pt->y);
1119                         }
1120                 }
1121         }
1122
1123         /* XXX if opponent is too close, go back, or wait ? */
1124
1125         /* go to nearest waypoint */
1126         trajectory_goto_xy_abs(&mainboard.traj, x, y);
1127         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1128         if (err == END_TIMER)
1129                 return err;
1130
1131         if (!TRAJ_SUCCESS(err))
1132                 return err;
1133
1134         strat_set_speed(old_dspeed, old_aspeed);
1135         strat_want_pack = 0;
1136         return END_TRAJ;
1137 }
1138
1139 void strat_avoid_init(void)
1140 {
1141         init_all_circuits();
1142
1143 #ifdef TEST_STRAT_AVOID
1144         uint8_t i, j;
1145         const struct circuit *selected_circuit;
1146         int8_t selected_face;
1147         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
1148         int8_t ret;
1149
1150         i = 1; j = 1;
1151         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1152
1153         ts = 0; bc = 0; cc = 0;
1154         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1155         find_best_circuit(i, j, &selected_circuit, &selected_face);
1156         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1157         dump_circuit_wp(circuit_wpline, ret);
1158
1159         ts = 0; bc = 3; cc = 0;
1160         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1161         find_best_circuit(i, j, &selected_circuit, &selected_face);
1162         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1163         dump_circuit_wp(circuit_wpline, ret);
1164
1165         ts = 0; bc = 4; cc = 0;
1166         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1167         find_best_circuit(i, j, &selected_circuit, &selected_face);
1168         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1169         dump_circuit_wp(circuit_wpline, ret);
1170
1171         ts = 0; bc = 3; cc = 5;
1172         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1173         find_best_circuit(i, j, &selected_circuit, &selected_face);
1174         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1175         dump_circuit_wp(circuit_wpline, ret);
1176
1177         ts = 0; bc = 4; cc = 5;
1178         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1179         find_best_circuit(i, j, &selected_circuit, &selected_face);
1180         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1181         dump_circuit_wp(circuit_wpline, ret);
1182
1183         ts = 80; bc = 0; cc = 0;
1184         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1185         find_best_circuit(i, j, &selected_circuit, &selected_face);
1186         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1187         dump_circuit_wp(circuit_wpline, ret);
1188
1189         i = 4; j = 3;
1190         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1191
1192         ts = 0; bc = 0; 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 = 0;
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 = 80; bc = 0; cc = 0;
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         i = 11; j = 6;
1211         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1212
1213         ts = 0; bc = 0; cc = 0;
1214         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1215         find_best_circuit(i, j, &selected_circuit, &selected_face);
1216         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1217         dump_circuit_wp(circuit_wpline, ret);
1218
1219         ts = 0; bc = 3; 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 = 80; bc = 0; 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 #endif
1231 }