vt100: include pgmspace.h as we use PROGMEM macro
[aversive.git] / projects / microb2010 / mainboard / strat.c
1 /*
2  *  Copyright Droids, Microb Technology (2009)
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 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27
28 #include <aversive/pgmspace.h>
29 #include <aversive/queue.h>
30 #include <aversive/wait.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 "cs.h"
62 #include "strat.h"
63 #include "strat_db.h"
64 #include "strat_base.h"
65 #include "strat_corn.h"
66 #include "strat_utils.h"
67 #include "strat_avoid.h"
68 #include "sensor.h"
69 #include "actuator.h"
70
71 #define COL_DISP_MARGIN 400 /* stop 40 cm in front of dispenser */
72 #define COL_SCAN_PRE_MARGIN 250
73
74 static volatile uint8_t strat_running = 0;
75 volatile uint8_t strat_want_pack = 0;
76 volatile uint8_t strat_lpack60 = 0;
77 volatile uint8_t strat_rpack60 = 0;
78
79 volatile uint8_t strat_opponent_lpack = 0;
80 volatile uint8_t strat_opponent_rpack = 0;
81
82 struct strat_conf strat_conf = {
83         .dump_enabled = 0,
84         .opp_orange = 90,
85         .orphan_tomato = 45,
86         .flags = 0,
87 };
88
89 /*************************************************************/
90
91 /*                  INIT                                     */
92
93 /*************************************************************/
94
95 /* called before each strat, and before the start switch */
96 void strat_preinit(void)
97 {
98         time_reset();
99         interrupt_traj_reset();
100         mainboard.flags =  DO_ENCODERS | DO_CS | DO_RS |
101                 DO_POS | DO_BD | DO_POWER;
102
103         strat_db_init();
104         strat_conf.prev_wait_obstacle = -5;
105         strat_conf_dump(__FUNCTION__);
106         strat_db_dump(__FUNCTION__);
107 }
108
109 void strat_conf_dump(const char *caller)
110 {
111         if (!strat_conf.dump_enabled)
112                 return;
113
114         printf_P(PSTR("-- conf --\r\n"));
115         printf_P(PSTR("our_orange = %s\r\n"),
116                  (strat_conf.flags & STRAT_CONF_OUR_ORANGE) ? "y":"n");
117         printf_P(PSTR("wait_obstacle = %s\r\n"),
118                  (strat_conf.flags & STRAT_CONF_WAIT_OBSTACLE) ? "y":"n");
119         printf_P(PSTR("straight begin = %s\r\n"),
120                  (strat_conf.flags & STRAT_CONF_STRAIGHT_BEGIN) ? "y":"n");
121         printf_P(PSTR("opp_orange = %d\r\n"), strat_conf.opp_orange);
122         printf_P(PSTR("orphan_tomato = %d\r\n"), strat_conf.orphan_tomato);
123 }
124
125 void strat_event_enable(void)
126 {
127         strat_running = 1;
128 }
129
130 void strat_event_disable(void)
131 {
132         strat_running = 0;
133 }
134
135 /* call it just before launching the strat */
136 void strat_init(void)
137 {
138 #ifdef HOST_VERSION
139         position_set(&mainboard.pos, 298.16,
140                      COLOR_Y(308.78), COLOR_A(70.00));
141 #endif
142
143         /* we consider that the color is correctly set */
144         strat_running = 1;
145         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
146         time_reset();
147         interrupt_traj_reset();
148
149         i2c_cobboard_deploy(I2C_LEFT_SIDE);
150         i2c_cobboard_deploy(I2C_RIGHT_SIDE);
151         i2c_cobboard_set_mode(I2C_COBBOARD_MODE_HARVEST);
152         i2c_ballboard_set_mode(I2C_BALLBOARD_MODE_HARVEST);
153
154         /* used in strat_base for END_TIMER */
155         mainboard.flags = DO_ENCODERS | DO_CS | DO_RS |
156                 DO_POS | DO_BD | DO_TIMER | DO_POWER;
157 }
158
159 /* call it after each strat */
160 void strat_exit(void)
161 {
162 #ifndef HOST_VERSION
163         uint8_t flags;
164 #endif
165
166         strat_running = 0;
167         mainboard.flags &= ~(DO_TIMER);
168         strat_hardstop();
169         time_reset();
170         wait_ms(100);
171 #ifndef HOST_VERSION
172         IRQ_LOCK(flags);
173         mainboard.flags &= ~(DO_CS);
174         IRQ_UNLOCK(flags);
175         pwm_ng_set(LEFT_PWM, 0);
176         pwm_ng_set(RIGHT_PWM, 0);
177 #endif
178 }
179
180 /* mark tomato as not present */
181 static void check_tomato(void)
182 {
183         int16_t x, y;
184         uint8_t i, j;
185         static uint8_t prev_check_time;
186         uint8_t cur_time;
187
188         /* check present tomatoes once per second */
189         cur_time = time_get_s();
190         if (cur_time != prev_check_time) {
191                 uint8_t k;
192
193                 for (k = 0; k < TOMATO_NB; k++) {
194                         if (strat_db.tomato_table[k]->present == 1 &&
195                             strat_db.tomato_table[k]->time_removed != -1 &&
196                             strat_db.tomato_table[k]->time_removed + 2 <= time_get_s()) {
197 #ifdef HOST_VERSION
198                                 printf("remove tomato %d\n", k);
199 #endif
200                                 strat_db.tomato_table[k]->present = 0;
201                         }
202                 }
203                 prev_check_time = cur_time;
204         }
205
206         x = position_get_x_s16(&mainboard.pos);
207         y = position_get_y_s16(&mainboard.pos);
208
209         if (xycoord_to_ijcoord(&x, &y, &i, &j) < 0)
210                 return;
211
212         if (strat_db.wp_table[i][j].type != WP_TYPE_TOMATO)
213                 return;
214
215         if (strat_db.wp_table[i][j].present == 0)
216                 return;
217
218         strat_db.wp_table[i][j].time_removed = time_get_s();
219         strat_db.wp_table[i][j].present = 0;
220 #ifdef HOST_VERSION
221         ballboard.ball_count ++;
222         printf("add ball %d,%d\n", i, j);
223 #endif
224 }
225
226 static void remove_cob(uint8_t idx)
227 {
228         if (strat_db.corn_table[idx]->corn.color == I2C_COB_BLACK)
229                 return;
230
231         if (strat_db.corn_table[idx]->time_removed == -1) {
232                 strat_db.corn_table[idx]->time_removed = time_get_s();
233 #ifdef HOST_VERSION
234                 cobboard.cob_count ++;
235                 printf("add cob %d\n", idx);
236 #endif
237         }
238 }
239
240 /* mark corn as not present and give correct commands to the cobboard
241  * for spickles */
242 static void check_corn(void)
243 {
244         uint8_t flags;
245         int8_t lcob_near, rcob_near;
246         uint8_t lcob, rcob;
247         uint8_t lidx, ridx;
248         static uint8_t prev_check_time;
249         uint8_t cur_time;
250         uint8_t need_lpack, need_rpack;
251         int16_t l_xspickle, l_yspickle;
252         int16_t r_xspickle, r_yspickle;
253         uint8_t l_y_too_high_pack = 0, r_y_too_high_pack = 0;
254
255         /* read sensors from ballboard */
256         IRQ_LOCK(flags);
257         lcob = ballboard.lcob;
258         ballboard.lcob = I2C_COB_NONE;
259         rcob = ballboard.rcob;
260         ballboard.rcob = I2C_COB_NONE;
261         IRQ_UNLOCK(flags);
262
263         /* check present cobs once per second */
264         cur_time = time_get_s();
265         if (cur_time != prev_check_time) {
266                 uint8_t i;
267
268                 /* only useful for simu */
269                 for (i = 0; i < CORN_NB; i++) {
270                         if (strat_db.corn_table[i]->present == 1 &&
271                             strat_db.corn_table[i]->time_removed != -1 &&
272                             strat_db.corn_table[i]->time_removed + 2 <= time_get_s()) {
273 #ifdef HOST_VERSION
274                                 printf("remove cob %d\n", i);
275 #endif
276                                 strat_db.corn_table[i]->present = 0;
277                         }
278                 }
279                 prev_check_time = cur_time;
280         }
281
282         /* detect cob on left side */
283         lcob_near = corn_is_near(&lidx, I2C_LEFT_SIDE,
284                                  &l_xspickle, &l_yspickle);
285         if (lcob_near && lcob != I2C_COB_NONE) {
286                 if (strat_db.corn_table[lidx]->corn.color == I2C_COB_UNKNOWN)
287                         DEBUG(E_USER_STRAT, "lcob %s %d",
288                               lcob == I2C_COB_WHITE ? "white" : "black", lidx);
289                 corn_set_color(strat_db.corn_table[lidx], lcob);
290         }
291         if (cur_time > 5 && !__y_is_more_than(l_yspickle, 600))
292                 l_y_too_high_pack = 1;
293
294         /* detect cob on right side */
295         rcob_near = corn_is_near(&ridx, I2C_RIGHT_SIDE,
296                                  &r_xspickle, &r_yspickle);
297         if (rcob_near && rcob != I2C_COB_NONE) {
298                 if (strat_db.corn_table[ridx]->corn.color == I2C_COB_UNKNOWN)
299                         DEBUG(E_USER_STRAT, "rcob %s %d",
300                               rcob == I2C_COB_WHITE ? "white" : "black", ridx);
301                 corn_set_color(strat_db.corn_table[ridx], rcob);
302         }
303         if (cur_time > 5 && !__y_is_more_than(r_yspickle, 600))
304                 r_y_too_high_pack = 1;
305
306         /* re-enable white cob */
307         if (lcob == I2C_COB_WHITE && lcob_near &&
308             strat_db.corn_table[lidx]->present == 0) {
309                 strat_db.corn_table[lidx]->present = 1;
310                 strat_db.corn_table[lidx]->time_removed = -1;
311         }
312         if (rcob == I2C_COB_WHITE && rcob_near &&
313             strat_db.corn_table[ridx]->present == 0) {
314                 strat_db.corn_table[ridx]->present = 1;
315                 strat_db.corn_table[ridx]->time_removed = -1;
316         }
317
318         /* control the cobboard mode for left spickle */
319         need_lpack = get_cob_count() >= 5 || strat_want_pack ||
320                 strat_lpack60 || strat_opponent_lpack || l_y_too_high_pack;
321
322         if (lcob_near &&
323             (strat_db.corn_table[lidx]->present ||
324              strat_db.corn_table[lidx]->time_removed == -1)) {
325                 if (need_lpack) {
326                         /* nothing  */
327                 }
328                 else {
329                         /* deploy spickle and harvest white ones */
330                         if (strat_db.corn_table[lidx]->corn.color == I2C_COB_WHITE)
331                                 i2c_cobboard_autoharvest_nomove(I2C_LEFT_SIDE);
332                         else
333                                 i2c_cobboard_deploy_nomove(I2C_LEFT_SIDE);
334                         remove_cob(lidx);
335                 }
336         }
337         else {
338                 /* no cob near us, we can pack or deploy freely */
339                 if (need_lpack)
340                         i2c_cobboard_pack_weak(I2C_LEFT_SIDE);
341                 else
342                         i2c_cobboard_deploy(I2C_LEFT_SIDE);
343         }
344
345         /* control the cobboard mode for right spickle */
346         need_rpack = get_cob_count() >= 5 || strat_want_pack ||
347                 strat_rpack60 || strat_opponent_rpack || r_y_too_high_pack;
348         if (rcob_near &&
349             (strat_db.corn_table[ridx]->present ||
350              strat_db.corn_table[ridx]->time_removed == -1)) {
351                 if (need_rpack) {
352                         /* nothing */
353                 }
354                 else {
355                         /* deploy spickle and harvest white ones */
356                         if (strat_db.corn_table[ridx]->corn.color == I2C_COB_WHITE)
357                                 i2c_cobboard_autoharvest_nomove(I2C_RIGHT_SIDE);
358                         else
359                                 i2c_cobboard_deploy_nomove(I2C_RIGHT_SIDE);
360                         remove_cob(ridx);
361                 }
362         }
363         else {
364                 /* no cob near us, we can pack or deploy freely */
365                 if (need_rpack)
366                         i2c_cobboard_pack_weak(I2C_RIGHT_SIDE);
367                 else
368                         i2c_cobboard_deploy(I2C_RIGHT_SIDE);
369         }
370 }
371
372 /* check opponent position */
373 void check_opponent(void)
374 {
375         int16_t opp_x, opp_y;
376         int16_t opp_d, opp_a;
377         uint8_t i, j;
378
379         strat_opponent_lpack = 0;
380         strat_opponent_rpack = 0;
381
382         if (get_opponent_xyda(&opp_x, &opp_y, &opp_d, &opp_a) < 0)
383                 return;
384
385         /* pack spickles if opponent too close */
386         if (opp_d < 600) {
387                 if (opp_a > 45 && opp_a < 135)
388                         strat_opponent_lpack = 1;
389                 if (opp_a > 225 && opp_a < 315)
390                         strat_opponent_rpack = 1;
391         }
392
393         /* check for oranges after 5 seconds */
394         if (time_get_s() > 5) {
395                 if (mainboard.our_color == I2C_COLOR_YELLOW) {
396                         if (opp_y < 500 && opp_x < 500)
397                                 strat_db.our_oranges_count = 0;
398                         if (opp_y < 500 && opp_x > AREA_X - 500)
399                                 strat_db.opp_oranges_count = 0;
400                 }
401                 else {
402                         if (opp_y > AREA_Y - 500 && opp_x < 500)
403                                 strat_db.our_oranges_count = 0;
404                         if (opp_y > AREA_Y - 500 && opp_x > AREA_X - 500)
405                                 strat_db.opp_oranges_count = 0;
406                 }
407         }
408
409         /* malus for some tomatoes and cobs, visited by opponent */
410         if (xycoord_to_ijcoord(&opp_x, &opp_y, &i, &j) < 0)
411                 return;
412
413         strat_db.wp_table[i][j].opp_visited = 1;
414 }
415
416 /* called periodically (10ms) */
417 void strat_event(void *dummy)
418 {
419         /* ignore when strat is not running */
420         if (strat_running == 0)
421                 return;
422
423         check_opponent();
424         check_tomato();
425         check_corn();
426
427         /* limit speed when opponent is near */
428         /* disabled for 2010, we are already slow :) */
429         //strat_limit_speed();
430 }
431
432 /* check that we are on an eject line */
433 static uint8_t robot_is_on_eject_line(void)
434 {
435         int16_t x, y;
436         uint8_t i, j;
437
438         x = position_get_x_s16(&mainboard.pos);
439         y = position_get_y_s16(&mainboard.pos);
440
441         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0)
442                 return 0;
443
444         if (!wp_belongs_to_line(i, j, 5, LINE_UP) &&
445             !wp_belongs_to_line(i, j, 2, LINE_R_UP))
446                 return 0;
447
448         return 1;
449 }
450
451 /* 0 = fast, 1 = slow */
452 static uint8_t eject_select_speed(void)
453 {
454         int16_t x, y;
455         uint8_t i, j;
456
457         x = position_get_x_s16(&mainboard.pos);
458         y = position_get_y_s16(&mainboard.pos);
459
460         if (get_cob_count() >= 5) {
461                 strat_want_pack = 1;
462                 return 0; /* fast */
463         }
464
465         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0) {
466                 DEBUG(E_USER_STRAT, "%s(): cannot find waypoint at %d,%d",
467                       __FUNCTION__, x, y);
468                 return 1; /* slow */
469         }
470
471         if (corn_count_neigh(i, j) == 2)
472                 return 1; /* slow */
473
474         return 0; /* fast */
475 }
476
477 /* called multiple times while we are waiting to reach the ejection
478  * point */
479 static uint8_t speedify_eject(void)
480 {
481         if (eject_select_speed())
482                 strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
483         else
484                 strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_SLOW);
485         return 0;
486 }
487
488 /* must be called from a terminal line */
489 static uint8_t strat_eject(void)
490 {
491         uint8_t err;
492
493         DEBUG(E_USER_STRAT, "%s() cob_count=%d ball_count=%d",
494               __FUNCTION__, get_cob_count(), get_ball_count());
495
496         /* check that we are called from an eject line */
497         if (!robot_is_on_eject_line()) {
498                 DEBUG(E_USER_STRAT, "%s() not on eject line", __FUNCTION__);
499                 return END_ERROR;
500         }
501
502         /* go to eject point */
503         trajectory_goto_forward_xy_abs(&mainboard.traj, 2625, COLOR_Y(1847));
504         err = WAIT_COND_OR_TRAJ_END(speedify_eject(),
505                                     TRAJ_FLAGS_NO_NEAR);
506         /* err is never == 0 because speedify_eject() always return 0 */
507         if (!TRAJ_SUCCESS(err))
508                 return err;
509
510         /* pack arms (force), and disable strat_event */
511         strat_event_disable();
512         i2c_cobboard_pack_weak(I2C_LEFT_SIDE);
513         i2c_cobboard_pack_weak(I2C_RIGHT_SIDE);
514
515         /* ball ejection */
516         if (get_ball_count() > 0) {
517                 i2c_ballboard_set_mode(I2C_BALLBOARD_MODE_EJECT);
518                 time_wait_ms(300);
519                 trajectory_a_abs(&mainboard.traj, COLOR_A(70));
520                 err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
521                 if (!TRAJ_SUCCESS(err))
522                         goto fail;
523
524                 DEBUG(E_USER_STRAT, "%s():%d", __FUNCTION__, __LINE__);
525                 strat_hardstop();
526 #ifdef HOST_VERSION
527                 time_wait_ms(2000);
528 #else
529                 WAIT_COND_OR_TIMEOUT(ballboard.status == I2C_BALLBOARD_STATUS_F_READY,
530                                      2000);
531 #endif
532         }
533         else {
534                 /* to pack spickles */
535                 time_wait_ms(300);
536         }
537
538         if (get_cob_count() > 0 ||
539             cobboard.status == I2C_COBBOARD_STATUS_LBUSY ||
540             cobboard.status == I2C_COBBOARD_STATUS_RBUSY) {
541                 /* half turn */
542                 trajectory_a_abs(&mainboard.traj, COLOR_A(-110));
543                 err = wait_traj_end(END_INTR|END_TRAJ);
544                 if (!TRAJ_SUCCESS(err))
545                         goto fail;
546
547                 /* cob ejection */
548                 trajectory_d_rel(&mainboard.traj, -70);
549                 err = wait_traj_end(END_INTR|END_TRAJ);
550                 if (!TRAJ_SUCCESS(err))
551                         goto fail;
552
553                 i2c_cobboard_set_mode(I2C_COBBOARD_MODE_EJECT);
554                 time_wait_ms(2000);
555
556
557                 /* cob ejection */
558                 trajectory_d_rel(&mainboard.traj, 70);
559                 err = wait_traj_end(END_INTR|END_TRAJ);
560                 if (!TRAJ_SUCCESS(err))
561                         goto fail;
562         }
563
564         strat_db_dump(__FUNCTION__);
565         err = END_TRAJ;
566
567  fail:
568         strat_event_enable();
569         strat_want_pack = 0;
570         return err;
571 }
572
573 static uint8_t strat_beginning(uint8_t do_initturn)
574 {
575         uint8_t err;
576
577         strat_set_acc(ACC_DIST, ACC_ANGLE);
578
579         if (do_initturn) {
580                 //strat_set_speed(600, 60);
581                 //strat_set_speed(450, 50);
582                 strat_set_speed(350, 40);
583                 trajectory_d_a_rel(&mainboard.traj, 1000, COLOR_A(20));
584                 err = WAIT_COND_OR_TRAJ_END(trajectory_angle_finished(&mainboard.traj),
585                                             TRAJ_FLAGS_STD);
586         }
587
588         strat_set_acc(ACC_DIST, ACC_ANGLE);
589         strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
590
591  l1:
592         err = line2line(0, LINE_UP, 2, LINE_R_DOWN, TRAJ_FLAGS_NO_NEAR);
593         if (err == END_OBSTACLE &&
594             strat_conf.flags & STRAT_CONF_WAIT_OBSTACLE &&
595             time_get_s() > strat_conf.prev_wait_obstacle + 5) {
596                 strat_conf.prev_wait_obstacle = time_get_s();
597                 time_wait_ms(2000);
598                 goto l1;
599         }
600         if (!TRAJ_SUCCESS(err))
601                 return err;
602
603  l2:
604         err = line2line(2, LINE_R_DOWN, 2, LINE_R_UP, TRAJ_FLAGS_NO_NEAR);
605         if (err == END_OBSTACLE &&
606             strat_conf.flags & STRAT_CONF_WAIT_OBSTACLE &&
607             time_get_s() > strat_conf.prev_wait_obstacle + 5) {
608                 strat_conf.prev_wait_obstacle = time_get_s();
609                 time_wait_ms(2000);
610                 goto l2;
611         }
612         if (!TRAJ_SUCCESS(err)) {
613                 return err;
614         }
615
616         return END_TRAJ;
617 }
618
619 static uint8_t strat_beginning2(uint8_t do_initturn)
620 {
621         uint8_t err;
622
623         strat_set_acc(ACC_DIST, ACC_ANGLE);
624
625         if (do_initturn) {
626                 strat_set_speed(600, 95); /* OK */
627                 trajectory_d_a_rel(&mainboard.traj, 1000, COLOR_A(-40));
628                 err = WAIT_COND_OR_TRAJ_END(trajectory_angle_finished(&mainboard.traj),
629                                             TRAJ_FLAGS_STD);
630                 if (err == 0)
631                         return END_TRAJ;
632         }
633         else {
634                 trajectory_goto_forward_xy_abs(&mainboard.traj,
635                                                375, COLOR_Y(597));
636                 err = wait_traj_end(TRAJ_FLAGS_STD);
637         }
638         return err;
639 }
640
641 /* dump state (every 5 s max) */
642 #define DUMP_RATE_LIMIT(dump, last_print)               \
643         do {                                            \
644                 if (time_get_s() - last_print > 5) {    \
645                         dump();                         \
646                         last_print = time_get_s();      \
647                 }                                       \
648         } while (0)
649
650
651 #if 0
652 /* return true if we need to grab some more elements */
653 static uint8_t need_more_elements(void)
654 {
655         if (time_get_s() <= 75) {
656                 /* we have enough time left */
657                 if (get_ball_count() >= 4)
658                         return 0;
659                 if (get_cob_count() >= 4)
660                         return 0;
661                 if ((get_ball_count() >= 2) &&
662                     (get_cob_count() >= 2))
663                         return 0;
664                 return 1;
665         }
666         else {
667                 /* not much time remaining */
668                 if ((get_ball_count() >= 1) &&
669                     (get_cob_count() >= 1))
670                         return 0;
671                 return 1;
672         }
673 }
674 #endif
675
676 /* get tomatoes near our goals (12,5 and 12,3) */
677 uint8_t get_opp_oranges(void)
678 {
679         int16_t x, y;
680         uint8_t i, j;
681         uint8_t err;
682
683         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
684
685         /* only if oranges are present */
686         if (strat_db.opp_oranges_count == 0)
687                 return END_TRAJ;
688
689         strat_db.opp_oranges_count = 0;
690         x = position_get_x_s16(&mainboard.pos);
691         y = position_get_y_s16(&mainboard.pos);
692
693         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0)
694                 return END_ERROR;
695
696         /* not on eject point */
697         if (i != 11 || j != 6)
698                 return END_ERROR;
699
700         strat_want_pack = 1;
701         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
702
703         /* turn in the correct direction */
704         trajectory_a_abs(&mainboard.traj, COLOR_A(-90));
705         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
706         if (!TRAJ_SUCCESS(err))
707                 goto fail;
708
709         trajectory_goto_forward_xy_abs(&mainboard.traj, 2625, COLOR_Y(597));
710         err = wait_traj_end(TRAJ_FLAGS_STD);
711         if (!TRAJ_SUCCESS(err))
712                 goto fail;
713
714         strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
715         trajectory_goto_forward_xy_abs(&mainboard.traj, 2750, COLOR_Y(250));
716         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
717         if (!TRAJ_SUCCESS(err))
718                 goto fail;
719
720         err = run_to_the_hills(get_opponent_color());
721
722  fail:
723         strat_want_pack = 0;
724         return err;
725 }
726
727 /* get tomatoes near our goals (12,5 and 12,3) */
728 uint8_t get_orphan_tomatoes(void)
729 {
730 #define CLITOID_TOMATO_RADIUS 100.
731 #define TOMATO_BACK_X 2780
732 #define TOMATO_BACK_LEN 200
733
734         int16_t x, y, a;
735         uint8_t i, j;
736         uint8_t err;
737         int8_t ret;
738
739         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
740
741         /* only go if both tomatoes are present */
742         if (!strat_db.wp_table[12][5].present ||
743             !strat_db.wp_table[12][3].present) {
744                 return END_TRAJ;
745         }
746
747         x = position_get_x_s16(&mainboard.pos);
748         y = position_get_y_s16(&mainboard.pos);
749
750         if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0)
751                 return END_ERROR;
752
753         /* not on eject point */
754         if (i != 11 || j != 6)
755                 return END_ERROR;
756
757         strat_want_pack = 1;
758         strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_SLOW);
759
760         /* turn in the correct direction */
761         trajectory_a_abs(&mainboard.traj, COLOR_A(-90));
762         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
763
764         /* clitoid to turn and take the first ball */
765         ret = trajectory_clitoid(&mainboard.traj, 2625, COLOR_Y(1847),
766                                  COLOR_A(-90), 150., COLOR_A(90), 0,
767                                  CLITOID_TOMATO_RADIUS, 3*125);
768         if (ret < 0) {
769                 err = END_ERROR;
770                 goto fail;
771         }
772
773         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
774         if (!TRAJ_SUCCESS(err))
775                 goto fail;
776
777         strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
778         err = strat_calib(300, END_TRAJ|END_BLOCKING);
779         a = position_get_a_deg_s16(&mainboard.pos);
780         if (ABS(a) < 10)
781                 strat_reset_pos(AREA_X - ROBOT_HALF_LENGTH_FRONT,
782                                 DO_NOT_SET_POS,
783                                 COLOR_A(0) + ROBOT_ANGLE_FRONT);
784
785         strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_FAST);
786         trajectory_d_rel(&mainboard.traj, -250);
787         err = WAIT_COND_OR_TRAJ_END(!x_is_more_than(TOMATO_BACK_X),
788                                     TRAJ_FLAGS_NO_NEAR);
789
790         if (err != 0 && !TRAJ_SUCCESS(err))
791                 goto fail;
792
793         trajectory_d_a_rel(&mainboard.traj, -TOMATO_BACK_LEN, COLOR_A(-90));
794         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
795
796         /* next ball */
797
798         /* clitoid to turn and take the first ball */
799         strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_SLOW);
800         ret = trajectory_clitoid(&mainboard.traj, 2625, COLOR_Y(1847),
801                                  COLOR_A(-90), 150., COLOR_A(90), 0,
802                                  CLITOID_TOMATO_RADIUS, 7*125);
803         if (ret < 0) {
804                 err = END_ERROR;
805                 goto fail;
806         }
807         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
808         if (!TRAJ_SUCCESS(err))
809                 goto fail;
810
811         strat_hardstop();
812         strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_FAST);
813         trajectory_d_rel(&mainboard.traj, -250);
814         err = WAIT_COND_OR_TRAJ_END(!x_is_more_than(TOMATO_BACK_X),
815                                     TRAJ_FLAGS_NO_NEAR);
816         trajectory_d_a_rel(&mainboard.traj, -TOMATO_BACK_LEN, COLOR_A(-90));
817         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
818
819 fail:
820         strat_want_pack = 0;
821         return err;
822 }
823
824
825 #define HILL_LEN 1000
826
827 #define HILL_ANGLE 0
828 #define HILL_POSY_YELLOW 310
829 #define HILL_POSY_BLUE 190
830
831 #define HILL_POSX_BALLS_DOWN1 830
832 #define HILL_POSX_BALLS_DOWN2 920
833 #define HILL_POSX_BALLS_DOWN3 730
834 #define HILL_START_POSX 580
835
836 uint8_t prepare_hill(uint8_t orange_color, int16_t posx)
837 {
838         int16_t startx, starty;
839         uint8_t our_color = get_color();
840         uint8_t err;
841
842         strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
843         if (orange_color == I2C_COLOR_YELLOW)
844                 starty = HILL_POSY_YELLOW;
845         else
846                 starty = HILL_POSY_BLUE;
847         if (orange_color == our_color)
848                 startx = posx;
849         else
850                 startx = AREA_X - posx;
851         trajectory_goto_forward_xy_abs(&mainboard.traj, startx, COLOR_Y(starty));
852         err = wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
853         if (!TRAJ_SUCCESS(err))
854                 return err;
855
856         /* turn to the hills */
857         if (orange_color == our_color)
858                 trajectory_a_abs(&mainboard.traj, COLOR_A(HILL_ANGLE));
859         else
860                 trajectory_a_abs(&mainboard.traj, COLOR_A(-180+HILL_ANGLE));
861         err = wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
862         if (!TRAJ_SUCCESS(err))
863                 return err;
864
865         return END_TRAJ;
866 }
867
868 /* get oranges, must be called near game area */
869 uint8_t run_to_the_hills(uint8_t orange_color)
870 {
871         double aa, ad;
872         uint16_t sa, sd;
873         uint8_t err;
874         uint8_t our_color = get_color();
875         int32_t p = pid_get_gain_P(&mainboard.angle.pid);
876         int32_t i = pid_get_gain_I(&mainboard.angle.pid);
877         int32_t d = pid_get_gain_D(&mainboard.angle.pid);
878         int32_t max_in = pid_get_max_in(&mainboard.angle.pid);
879         int32_t max_i = pid_get_max_I(&mainboard.angle.pid);
880         int32_t max_out = pid_get_max_out(&mainboard.angle.pid);
881
882         strat_want_pack = 1;
883         strat_get_acc(&ad, &aa);
884         strat_get_speed(&sd, &sa);
885
886         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
887
888         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
889         err = prepare_hill(orange_color, HILL_START_POSX);
890         if (!TRAJ_SUCCESS(err))
891                 return err;
892
893         strat_set_acc(5, ACC_ANGLE);
894         strat_set_speed(300, SPEED_ANGLE_SLOW);
895         bd_set_current_thresholds(&mainboard.distance.bd, 500, 8000, 2000000, 80);
896         bd_set_current_thresholds(&mainboard.angle.bd, 500, 8000, 2000000, 80);
897         bd_set_speed_threshold(&mainboard.distance.bd, 10);
898         support_balls_pack();
899
900         /* decrease angle gains */
901         pid_set_gains(&mainboard.angle.pid, 200, 0, 2000);
902
903         /* here it is difficult to handle return values, because we
904          * are on the hill */
905         i2c_cobboard_set_mode(I2C_COBBOARD_MODE_KICKSTAND_DOWN);
906         trajectory_d_rel(&mainboard.traj, HILL_LEN);
907         if (orange_color == our_color)
908                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) >
909                                             HILL_POSX_BALLS_DOWN1,
910                                             TRAJ_FLAGS_SMALL_DIST);
911         else
912                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) <
913                                             AREA_X - HILL_POSX_BALLS_DOWN1,
914                                             TRAJ_FLAGS_SMALL_DIST);
915         DEBUG(E_USER_STRAT, "deploy support balls");
916         i2c_ballboard_set_mode(I2C_BALLBOARD_MODE_PREP_FORK);
917         support_balls_deploy();
918         i2c_cobboard_set_mode(I2C_COBBOARD_MODE_KICKSTAND_UP);
919         trajectory_only_a_rel(&mainboard.traj, 2);
920         err = WAIT_COND_OR_TE_TO(0, 0, 2200);
921
922         i2c_cobboard_set_mode(I2C_COBBOARD_MODE_KICKSTAND_DOWN);
923         strat_set_acc(3, 3);
924         strat_hardstop();
925         i2c_ballboard_set_mode(I2C_BALLBOARD_MODE_TAKE_FORK);
926
927         time_wait_ms(500);
928
929         trajectory_d_rel(&mainboard.traj, 15);
930         time_wait_ms(700);
931         strat_hardstop();
932         time_wait_ms(200);
933
934         /* reach top, go down */
935         trajectory_d_a_rel(&mainboard.traj, -HILL_LEN, -2);
936
937         if (orange_color == our_color)
938                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) <
939                                             HILL_POSX_BALLS_DOWN2,
940                                             TRAJ_FLAGS_SMALL_DIST);
941         else
942                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) >
943                                             AREA_X - HILL_POSX_BALLS_DOWN2,
944                                             TRAJ_FLAGS_SMALL_DIST);
945         DEBUG(E_USER_STRAT, "pack support balls");
946         support_balls_pack();
947         if (orange_color == our_color)
948                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) <
949                                             HILL_POSX_BALLS_DOWN3,
950                                             TRAJ_FLAGS_SMALL_DIST);
951         else
952                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) >
953                                             AREA_X - HILL_POSX_BALLS_DOWN3,
954                                             TRAJ_FLAGS_SMALL_DIST);
955
956         DEBUG(E_USER_STRAT, "deploy support balls");
957         support_balls_deploy();
958
959         if (orange_color == I2C_COLOR_YELLOW) {
960                 strat_set_acc(ad, aa);
961                 strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
962         }
963         else {
964                 strat_set_acc(ad, 0.4);
965                 strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
966                 trajectory_d_a_rel(&mainboard.traj, -500, 20);
967         }
968
969         /* wait to be near the wall */
970         if (orange_color == our_color)
971                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) < 300,
972                                             TRAJ_FLAGS_SMALL_DIST);
973         else
974                 err = WAIT_COND_OR_TRAJ_END(position_get_x_s16(&mainboard.pos) >
975                                             AREA_X - 300,
976                                             TRAJ_FLAGS_SMALL_DIST);
977
978         strat_set_acc(ad, aa);
979         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
980
981         /* restore BD coefs */
982         bd_set_current_thresholds(&mainboard.distance.bd, 500, 8000, 1000000, 20);
983         bd_set_current_thresholds(&mainboard.distance.bd, 500, 8000, 1000000, 20);
984         bd_set_speed_threshold(&mainboard.distance.bd, 60);
985
986         /* calibrate position on the wall */
987         strat_set_speed(SPEED_DIST_VERY_SLOW, SPEED_ANGLE_SLOW);
988
989         i2c_cobboard_set_mode(I2C_COBBOARD_MODE_HARVEST);
990
991         trajectory_a_abs(&mainboard.traj, COLOR_A(-90));
992         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
993         time_wait_ms(200);
994
995         err = strat_calib(400, TRAJ_FLAGS_SMALL_DIST);
996         strat_reset_pos(DO_NOT_SET_POS,
997                         COLOR_Y(ROBOT_HALF_LENGTH_FRONT),
998                         COLOR_A(-90) + ROBOT_ANGLE_FRONT);
999         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
1000
1001         trajectory_d_rel(&mainboard.traj, -250);
1002         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1003 #if 0
1004         if (orange_color == our_color)
1005                 trajectory_a_abs(&mainboard.traj, 180);
1006         else
1007                 trajectory_a_abs(&mainboard.traj, 0);
1008         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1009         time_wait_ms(200);
1010
1011         strat_set_speed(SPEED_DIST_VERY_SLOW, SPEED_ANGLE_FAST);
1012         err = strat_calib(400, TRAJ_FLAGS_SMALL_DIST);
1013         if (orange_color == our_color)
1014                 strat_reset_pos(ROBOT_HALF_LENGTH_FRONT,
1015                                 DO_NOT_SET_POS,
1016                                 180 + ROBOT_ANGLE_FRONT);
1017         else
1018                 strat_reset_pos(AREA_X - ROBOT_HALF_LENGTH_FRONT,
1019                                 DO_NOT_SET_POS,
1020                                 0 + ROBOT_ANGLE_FRONT);
1021         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
1022
1023         trajectory_d_rel(&mainboard.traj, -250);
1024         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1025 #endif
1026         /* revert acceleration and speed */
1027         pid_set_gains(&mainboard.angle.pid, p, i, d);
1028         pid_set_maximums(&mainboard.distance.pid, max_in, max_i, max_out);
1029         strat_want_pack = 0;
1030         strat_set_speed(sd, sa);
1031         support_balls_deploy();
1032         return err;
1033 }
1034
1035 uint8_t strat_main(void)
1036 {
1037         uint8_t err, do_initturn = 1;
1038
1039         /* get oranges */
1040         if (strat_conf.flags & STRAT_CONF_OUR_ORANGE) {
1041                 err = run_to_the_hills(get_color());
1042                 strat_db.our_oranges_count = 0;
1043                 do_initturn = 0;
1044         }
1045
1046         /* harvest the first cobs + balls */
1047         if (strat_conf.flags & STRAT_CONF_STRAIGHT_BEGIN)
1048                 err = strat_beginning2(do_initturn);
1049         else
1050                 err = strat_beginning(do_initturn);
1051
1052         if (!TRAJ_SUCCESS(err))
1053                 strat_unblock();
1054         else
1055                 err = strat_eject();
1056
1057         /* choose circuit, and harvest on it */
1058         while (1) {
1059
1060                 DEBUG(E_USER_STRAT, "start main loop");
1061
1062                 /* if it's time to get tomatoes, do it */
1063                 if (time_get_s() > strat_conf.orphan_tomato) {
1064                         err = get_orphan_tomatoes();
1065                         if (err == END_ERROR) {
1066                                 DEBUG(E_USER_STRAT,
1067                                       "get_orphan_tomatoes returned END_ERROR");
1068                         }
1069                         else if (err == END_TIMER) {
1070                                 DEBUG(E_USER_STRAT, "End of time");
1071                                 strat_exit();
1072                                 break;
1073                         }
1074                         else if (!TRAJ_SUCCESS(err)) {
1075                                 /* don't retry these tomatoes if it failed */
1076                                 strat_conf.orphan_tomato = 90;
1077                                 strat_unblock();
1078                         }
1079                 }
1080
1081                 /* if it's time to get opponent oranges, do it */
1082                 if (time_get_s() > strat_conf.opp_orange) {
1083                         err = get_opp_oranges();
1084                         if (err == END_ERROR) {
1085                                 DEBUG(E_USER_STRAT,
1086                                       "get_opp_oranges returned END_ERROR");
1087                         }
1088                         else if (err == END_TIMER) {
1089                                 DEBUG(E_USER_STRAT, "End of time");
1090                                 strat_exit();
1091                                 break;
1092                         }
1093                         else if (!TRAJ_SUCCESS(err)) {
1094                                 /* don't retry oranges if it failed */
1095                                 strat_conf.opp_orange = 90;
1096                                 strat_unblock();
1097                         }
1098                 }
1099
1100                 /**********************/
1101                 /* harvest on circuit */
1102                 /**********************/
1103
1104                 err = strat_harvest_circuit();
1105                 if (err == END_TIMER) {
1106                         DEBUG(E_USER_STRAT, "End of time");
1107                         strat_exit();
1108                         break;
1109                 }
1110                 if (!TRAJ_SUCCESS(err)) {
1111                         strat_unblock();
1112                         continue;
1113                 }
1114
1115                 /***********************/
1116                 /* eject game elements */
1117                 /***********************/
1118
1119                 err = strat_eject();
1120                 /* end of time exit ! */
1121                 if (err == END_TIMER) {
1122                         DEBUG(E_USER_STRAT, "End of time");
1123                         strat_exit();
1124                         break;
1125                 }
1126                 if (!TRAJ_SUCCESS(err)) {
1127                         strat_unblock();
1128                         continue;
1129                 }
1130         }
1131
1132         return err;
1133 }