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