2 * Copyright Droids, Microb Technology (2009)
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.
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.
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
18 * Revision : $Id: strat_scan.c,v 1.2 2009-11-08 17:24:33 zer0 Exp $
20 * Olivier MATZ <zer0@droids-corp.org>
28 #include <aversive/pgmspace.h>
29 #include <aversive/queue.h>
30 #include <aversive/wait.h>
31 #include <aversive/error.h>
41 #include <control_system_manager.h>
42 #include <trajectory_manager.h>
43 #include <vect_base.h>
46 #include <obstacle_avoidance.h>
47 #include <blocking_detection_manager.h>
48 #include <robot_system.h>
49 #include <position_manager.h>
55 #include "../common/i2c_commands.h"
58 #include "i2c_protocol.h"
60 #include "strat_base.h"
61 #include "strat_utils.h"
62 #include "strat_avoid.h"
65 #define ERROUT(e) do { \
71 void scanner_dump_state(void)
75 printf_P(PSTR("scanner state:\r\n"));
76 status = sensorboard.scan_status;
78 printf_P(PSTR(" status=%x: "), sensorboard.scan_status);
80 if (status & I2C_SCAN_DONE)
81 printf_P(PSTR("DONE "));
83 printf_P(PSTR("RUNNING "));
84 if (status & I2C_SCAN_MAX_COLUMN)
85 printf_P(PSTR("OBSTACLE "));
87 printf_P(PSTR("\r\n"));
89 if (sensorboard.dropzone_h == -1) {
90 printf_P(PSTR("No zone found\r\n"));
94 printf_P(PSTR(" column_h=%d\r\n"), sensorboard.dropzone_h);
95 printf_P(PSTR(" column_x=%d\r\n"), sensorboard.dropzone_x);
96 printf_P(PSTR(" column_y=%d\r\n"), sensorboard.dropzone_y);
99 /* must be larger than the disc poly */
100 #define CHECKPOINT_DIST 600
102 /* go to a specific angle on disc, if level == -1, don't move arms */
103 uint8_t strat_goto_disc_angle(int16_t a_deg, int8_t level)
106 uint16_t old_spdd, old_spda;
108 uint8_t need_clear = 0;
110 DEBUG(E_USER_STRAT, "%s(a_deg=%d, level=%d)", __FUNCTION__,
113 strat_get_speed(&old_spdd, &old_spda);
114 strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
116 /* workaround for some static cols configurations */
117 if ((strat_infos.conf.flags & STRAT_CONF_EARLY_SCAN) == 0) {
118 if (time_get_s() > 15)
119 i2c_mechboard_mode_loaded();
121 /* another workaround for offensive configuration */
123 if (strat_infos.i2c_loaded_skipped == 0) {
124 DEBUG(E_USER_STRAT, "%s() need clear");
125 strat_infos.i2c_loaded_skipped = 1;
126 i2c_mechboard_mode_prepare_pickup_next(I2C_AUTO_SIDE,
127 I2C_MECHBOARD_MODE_CLEAR);
131 i2c_mechboard_mode_loaded();
135 /* calculate the checkpoint */
138 rotate(&x, &y, RAD(a_deg));
142 err = goto_and_avoid(x, y, TRAJ_FLAGS_STD,
144 if (!TRAJ_SUCCESS(err))
147 /* early offensive conf only */
149 err = WAIT_COND_OR_TIMEOUT(get_column_count() == 2,
151 DEBUG(E_USER_STRAT, "%s() offensive: err=%d", err);
152 if (err == 0) /* timeout */
155 err = strat_goto_disc(level);
158 strat_set_speed(old_spdd, old_spda);
163 /* only valid for temple on disc */
164 int16_t strat_get_temple_angle(struct temple *temple)
177 #define SCAN_ANGLE_OFFSET (-40)
178 int16_t strat_temple_angle_to_scan_angle(int16_t temple_angle)
180 return temple_angle + SCAN_ANGLE_OFFSET;
183 /* start to scan after this distance */
184 #define DIST_START_SCAN 50
186 /* scan during this distance (includes DIST_START_SCAN) */
187 #define DIST_SCAN 430
189 /* speed of the scan */
190 #define SPEED_SCAN 450
192 /* from scanner point of view */
193 #define DISC_CENTER_X 15
194 #define DISC_CENTER_Y 13
196 /* distance of the checkpoint */
197 #define CKPT_DST 550.
199 /* to convert in robot coordinates */
200 #define SIDE_OFFSET (ROBOT_WIDTH/2)
201 #define DIST_OFFSET (DIST_SCAN - DIST_START_SCAN)
203 /* center of the disc in robot coordinates */
204 #define CENTER_X_SCANNER 166
205 #define CENTER_Y_SCANNER 174
207 /* center of the disc in scanner millimeters coordinates */
208 #define CENTER_X_SCANNER2 120
209 #define CENTER_Y_SCANNER2 155
211 /* structure filled by strat_scan_disc() */
212 struct scan_disc_result {
213 #define SCAN_FAILED 0
217 #define SCAN_ACTION_BUILD_TEMPLE 0
218 #define SCAN_ACTION_BUILD_COL 1
224 #define SCAN_MODE_CHECK_TEMPLE 0
225 #define SCAN_MODE_SCAN_COL 1
226 #define SCAN_MODE_SCAN_TEMPLE 2
228 int8_t strat_scan_get_checkpoint(uint8_t mode, int16_t *ckpt_rel_x,
229 int16_t *ckpt_rel_y, int16_t *back_mm)
231 int16_t center_rel_x, center_rel_y;
232 int16_t col_rel_x, col_rel_y;
233 int16_t col_vect_x, col_vect_y;
234 double col_vect_norm;
235 int16_t ckpt_vect_x, ckpt_vect_y;
237 /* do some filtering */
238 if (mode == SCAN_MODE_SCAN_TEMPLE &&
239 sensorboard.dropzone_x > CENTER_X_SCANNER) {
240 DEBUG(E_USER_STRAT, "x too big");
244 /* process relative pos from robot point of view */
245 center_rel_x = DIST_OFFSET - CENTER_Y_SCANNER;
246 center_rel_y = -(SIDE_OFFSET + CENTER_X_SCANNER);
248 col_rel_x = DIST_OFFSET - sensorboard.dropzone_y;
249 col_rel_y = -(SIDE_OFFSET + sensorboard.dropzone_x);
250 DEBUG(E_USER_STRAT, "col_rel = %d,%d", col_rel_x, col_rel_y);
252 /* vector from center to column */
253 col_vect_x = col_rel_x - center_rel_x;
254 col_vect_y = col_rel_y - center_rel_y;
255 col_vect_norm = norm(col_vect_x, col_vect_y);
257 /* vector from center to ckpt */
258 ckpt_vect_x = (double)(col_vect_x) * CKPT_DST / col_vect_norm;
259 ckpt_vect_y = (double)(col_vect_y) * CKPT_DST / col_vect_norm;
261 /* rel pos of ckpt */
262 *ckpt_rel_x = center_rel_x + ckpt_vect_x;
263 *ckpt_rel_y = center_rel_y + ckpt_vect_y;
265 /* do some filtering */
266 if (col_vect_norm > 150 || col_vect_norm < 30) {
267 DEBUG(E_USER_STRAT, "bad norm");
271 if (mode == SCAN_MODE_SCAN_TEMPLE) {
272 if (col_vect_norm > 50) {
273 *back_mm = ABS(col_vect_norm-50);
280 * scan the disc: return END_TRAJ on success (and status in result is
281 * set to SCAN_VALID). In this case, all the scan_disc_result
282 * structure is filled with appropriate parameters. mode can be
283 * 'check' or 'scan_col'. Note that if we do a check_temple, the level
284 * field in structure must be filled first by the caller.
286 uint8_t strat_scan_disc(int16_t angle, uint8_t mode,
287 struct scan_disc_result *result)
289 uint16_t old_spdd, old_spda;
290 uint8_t err, stop_scanner = 0;
291 uint8_t original_mode = mode;
292 int16_t pos1x, pos1y, dist;
295 int16_t ckpt_rel_x = 0, ckpt_rel_y = 0;
297 double center_abs_x, center_abs_y;
298 double ckpt_rel_d, ckpt_rel_a;
299 double ckpt_abs_x, ckpt_abs_y;
301 /* mark status as failed for now */
302 result->status = SCAN_FAILED;
304 DEBUG(E_USER_STRAT, "%s(angle=%d)", __FUNCTION__, angle);
306 strat_get_speed(&old_spdd, &old_spda);
309 err = strat_goto_disc_angle(angle, -1);
310 if (!TRAJ_SUCCESS(err))
313 /* wait opponent before scanning */
314 if (strat_infos.conf.wait_opponent > 0) {
315 int16_t opp_x, opp_y, opp_d, opp_a;
320 while ((err = get_opponent_xyda(&opp_x, &opp_y,
321 &opp_d, &opp_a)) == 0) {
327 if (time_get_us2() - us >= (uint32_t)strat_infos.conf.wait_opponent * 1000000L)
332 /* save absolute position of disc */
333 rel_da_to_abs_xy(265, 0, ¢er_abs_x, ¢er_abs_y);
335 strat_limit_speed_disable();
337 /* go back and prepare to scan */
338 strat_set_speed(1000, 1000);
339 trajectory_d_a_rel(&mainboard.traj, -140, 130);
340 err = wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
341 if (!TRAJ_SUCCESS(err))
344 /* XXX check that opp is not behind us */
346 /* prepare scanner */
349 i2c_sensorboard_scanner_prepare();
350 time_wait_ms(250); /* XXX to remove ? */
352 strat_set_speed(SPEED_SCAN, 1000);
354 pos1x = position_get_x_s16(&mainboard.pos);
355 pos1y = position_get_y_s16(&mainboard.pos);
356 trajectory_d_rel(&mainboard.traj, -DIST_SCAN);
359 err = test_traj_end(TRAJ_FLAGS_SMALL_DIST);
363 dist = distance_from_robot(pos1x, pos1y);
365 if (dist > DIST_START_SCAN)
368 if (get_scanner_status() & I2C_SCAN_MAX_COLUMN) {
375 if (TRAJ_SUCCESS(err))
376 err = END_ERROR; /* should not reach end */
378 trajectory_goto_xy_abs(&mainboard.traj, pos1x, pos1y);
379 wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
383 /* start the scanner */
385 i2c_sensorboard_scanner_start();
387 err = WAIT_COND_OR_TRAJ_END(get_scanner_status() & I2C_SCAN_MAX_COLUMN,
391 if (!TRAJ_SUCCESS(err)) {
393 trajectory_goto_xy_abs(&mainboard.traj, pos1x, pos1y);
394 wait_traj_end(TRAJ_FLAGS_NO_NEAR);
398 wait_scan_done(1000);
400 i2c_sensorboard_scanner_stop();
403 if (mode == SCAN_MODE_CHECK_TEMPLE) {
404 i2c_sensorboard_scanner_algo_check(result->level,
407 i2cproto_wait_update();
408 wait_scan_done(1000);
409 scanner_dump_state();
411 if (sensorboard.dropzone_h == -1 &&
412 !(strat_infos.conf.flags & STRAT_CONF_SKIP_WHEN_CHECK_FAILS)) {
413 DEBUG(E_USER_STRAT, "-- try to build a temple");
414 mode = SCAN_MODE_SCAN_TEMPLE;
417 result->action = SCAN_ACTION_BUILD_TEMPLE;
418 /* level is already set by caller */
422 if (mode == SCAN_MODE_SCAN_TEMPLE) {
423 i2c_sensorboard_scanner_algo_temple(I2C_SCANNER_ZONE_DISC,
426 i2cproto_wait_update();
427 wait_scan_done(1000);
428 scanner_dump_state();
430 if (sensorboard.dropzone_h == -1 ||
431 strat_scan_get_checkpoint(mode, &ckpt_rel_x,
432 &ckpt_rel_y, &back_mm)) {
433 if (original_mode != SCAN_MODE_CHECK_TEMPLE) {
434 DEBUG(E_USER_STRAT, "-- try to build a column");
435 mode = SCAN_MODE_SCAN_COL;
438 DEBUG(E_USER_STRAT, "-- check failed");
442 result->action = SCAN_ACTION_BUILD_TEMPLE;
443 result->level = sensorboard.dropzone_h;
447 if (mode == SCAN_MODE_SCAN_COL) {
448 i2c_sensorboard_scanner_algo_column(I2C_SCANNER_ZONE_DISC,
451 i2cproto_wait_update();
452 wait_scan_done(1000);
453 scanner_dump_state();
455 if (sensorboard.dropzone_h == -1 ||
456 strat_scan_get_checkpoint(mode, &ckpt_rel_x,
457 &ckpt_rel_y, &back_mm)) {
461 result->action = SCAN_ACTION_BUILD_COL;
462 result->level = sensorboard.dropzone_h;
466 if (sensorboard.dropzone_h == -1) {
470 if (mode == SCAN_MODE_CHECK_TEMPLE) {
475 DEBUG(E_USER_STRAT, "rel xy for ckpt is %d,%d", ckpt_rel_x, ckpt_rel_y);
477 rel_xy_to_abs_xy(ckpt_rel_x, ckpt_rel_y, &ckpt_abs_x, &ckpt_abs_y);
478 abs_xy_to_rel_da(ckpt_abs_x, ckpt_abs_y, &ckpt_rel_d, &ckpt_rel_a);
480 DEBUG(E_USER_STRAT, "abs ckpt is %2.2f,%2.2f", ckpt_abs_x, ckpt_abs_y);
482 strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
484 /* intermediate checkpoint for some positions */
485 if ( (DEG(ckpt_rel_a) < 0 && DEG(ckpt_rel_a) > -90) ) {
486 trajectory_goto_xy_rel(&mainboard.traj, 200, 100);
487 err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
488 if (!TRAJ_SUCCESS(err))
492 trajectory_goto_xy_abs(&mainboard.traj, ckpt_abs_x, ckpt_abs_y);
493 err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
494 if (!TRAJ_SUCCESS(err))
497 if (result->action == SCAN_ACTION_BUILD_TEMPLE) {
498 i2c_mechboard_mode_prepare_build_both(result->level);
501 trajectory_turnto_xy(&mainboard.traj, center_abs_x, center_abs_y);
502 err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
503 if (!TRAJ_SUCCESS(err))
506 pos1x = position_get_x_s16(&mainboard.pos);
507 pos1y = position_get_y_s16(&mainboard.pos);
509 strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
510 trajectory_d_rel(&mainboard.traj, 400);
511 err = WAIT_COND_OR_TRAJ_END(distance_from_robot(pos1x, pos1y) > 200,
512 TRAJ_FLAGS_SMALL_DIST);
514 strat_set_speed(SPEED_DIST_VERY_SLOW, SPEED_ANGLE_VERY_SLOW);
515 trajectory_d_rel(&mainboard.traj, 400);
516 err = wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
518 if (TRAJ_SUCCESS(err))
519 err = END_ERROR; /* should not reach end */
520 if (err != END_BLOCKING && !TRAJ_SUCCESS(err))
524 trajectory_d_rel(&mainboard.traj, -back_mm);
525 wait_traj_end(TRAJ_FLAGS_SMALL_DIST);
528 result->status = SCAN_VALID;
530 strat_limit_speed_enable();
535 i2c_sensorboard_scanner_stop();
536 strat_limit_speed_enable();
537 strat_set_speed(old_spdd, old_spda);
542 /* do action according to scanner result. temple argument can be NULL
543 * if it's a new one (from opponent) or it can be our previous
545 uint8_t strat_scan_do_action(struct scan_disc_result *scan_result,
546 struct temple *temple, struct build_zone *zone)
550 /* remove the temple from the list */
551 if (scan_result->status != SCAN_VALID)
555 /* we were scanning a temple, remove it */
556 if (scan_result->level != temple->level_l) {
562 if (temple == NULL) {
563 temple = strat_get_free_temple();
566 memset(temple, 0, sizeof(*temple));
567 temple->level_l = scan_result->level;
568 temple->level_r = scan_result->level;
569 temple->flags = TEMPLE_F_OPPONENT |
570 TEMPLE_F_VALID | TEMPLE_F_LINTEL;
573 zone->flags |= ZONE_F_BUSY;
575 switch (scan_result->action) {
577 case SCAN_ACTION_BUILD_COL:
578 err = strat_grow_temple_column(temple);
581 case SCAN_ACTION_BUILD_TEMPLE:
582 err = strat_grow_temple(temple);
588 if (!TRAJ_SUCCESS(err))
593 uint8_t strat_build_on_opponent_temple(void)
595 struct temple *temple;
597 struct scan_disc_result scan_result;
598 int16_t temple_angle;
600 if (time_get_s() < strat_infos.conf.scan_opp_min_time)
603 strat_infos.conf.scan_opp_min_time =
604 time_get_s() + strat_infos.conf.delay_between_opp_scan;
606 /* scan on disc only */
607 if (strat_infos.conf.scan_opp_angle == -1) {
608 temple = strat_get_our_temple_on_disc(0);
610 /* scan the opposite of our temple if we found
613 temple_angle = strat_get_temple_angle(temple);
615 if (temple_angle > 180)
618 /* else scan at 0 deg (opponent side) */
624 /* user specified scan position */
625 temple_angle = strat_infos.conf.delay_between_opp_scan;
626 if (temple_angle > 180)
629 temple_angle = strat_temple_angle_to_scan_angle(temple_angle);
632 err = strat_scan_disc(temple_angle, SCAN_MODE_SCAN_TEMPLE,
634 if (!TRAJ_SUCCESS(err))
637 /* XXX on disc only */
638 err = strat_scan_do_action(&scan_result, NULL,
639 &strat_infos.zone_list[0]);
641 if (!TRAJ_SUCCESS(err))
644 err = strat_escape(&strat_infos.zone_list[0], TRAJ_FLAGS_STD);
648 uint8_t strat_check_temple_and_build(void)
650 struct temple *temple;
652 struct scan_disc_result scan_result;
653 int16_t temple_angle;
655 if (time_get_s() < strat_infos.conf.scan_our_min_time)
657 strat_infos.conf.scan_our_min_time =
658 time_get_s() + strat_infos.conf.delay_between_our_scan;
660 /* on disc only, symetric only */
661 temple = strat_get_our_temple_on_disc(1);
665 temple_angle = strat_get_temple_angle(temple);
666 temple_angle = strat_temple_angle_to_scan_angle(temple_angle);
668 scan_result.level = temple->level_l;
669 err = strat_scan_disc(temple_angle, SCAN_MODE_CHECK_TEMPLE,
671 if (scan_result.status != SCAN_VALID) {
675 /* no column after a temple check */
676 else if (scan_result.action == SCAN_ACTION_BUILD_COL &&
679 if (!TRAJ_SUCCESS(err))
682 err = strat_scan_do_action(&scan_result, temple,
684 if (!TRAJ_SUCCESS(err))
687 err = strat_escape(&strat_infos.zone_list[0], TRAJ_FLAGS_STD);