2 * Copyright Droids Corporation, 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_avoid.c,v 1.5 2009-11-08 17:24:33 zer0 Exp $
27 #include <aversive/pgmspace.h>
28 #include <aversive/wait.h>
29 #include <aversive/error.h>
36 #include <control_system_manager.h>
37 #include <trajectory_manager.h>
38 #include <vect_base.h>
41 #include <obstacle_avoidance.h>
42 #include <blocking_detection_manager.h>
43 #include <robot_system.h>
44 #include <position_manager.h>
51 #include "strat_base.h"
52 #include "strat_utils.h"
55 void set_rotated_pentagon(poly_t *pol, const point_t *robot_pt,
56 int16_t radius, int16_t x, int16_t y)
61 double px1, py1, px2, py2;
64 a_rad = atan2(y - robot_pt->y, x - robot_pt->x);
66 /* generate pentagon */
67 c_a = cos(-2*M_PI/EDGE_NUMBER);
68 s_a = sin(-2*M_PI/EDGE_NUMBER);
74 px1 = radius * cos(a_rad + 2*M_PI/(2*EDGE_NUMBER));
75 py1 = radius * sin(a_rad + 2*M_PI/(2*EDGE_NUMBER));
78 for (i = 0; i < EDGE_NUMBER; i++){
79 oa_poly_set_point(pol, x + px1, y + py1, i);
81 px2 = px1*c_a + py1*s_a;
82 py2 = -px1*s_a + py1*c_a;
89 void set_rotated_poly(poly_t *pol, const point_t *robot_pt,
90 int16_t w, int16_t l, int16_t x, int16_t y)
95 a_rad = atan2(y - robot_pt->y, x - robot_pt->x);
97 DEBUG(E_USER_STRAT, "%s() x,y=%d,%d a_rad=%2.2f",
98 __FUNCTION__, x, y, a_rad);
103 rotate(&tmp_x, &tmp_y, a_rad);
106 oa_poly_set_point(pol, tmp_x, tmp_y, 0);
111 rotate(&tmp_x, &tmp_y, a_rad);
114 oa_poly_set_point(pol, tmp_x, tmp_y, 1);
119 rotate(&tmp_x, &tmp_y, a_rad);
122 oa_poly_set_point(pol, tmp_x, tmp_y, 2);
127 rotate(&tmp_x, &tmp_y, a_rad);
130 oa_poly_set_point(pol, tmp_x, tmp_y, 3);
133 #define DISC_X CENTER_X
134 #define DISC_Y CENTER_Y
136 void set_central_disc_poly(poly_t *pol, const point_t *robot_pt)
138 set_rotated_pentagon(pol, robot_pt, DISC_PENTA_DIAG,
152 void set_opponent_poly(poly_t *pol, const point_t *robot_pt, int16_t w, int16_t l)
155 get_opponent_xy(&x, &y);
156 DEBUG(E_USER_STRAT, "oponent at: %d %d", x, y);
158 /* place poly even if invalid, because it's -100 */
159 set_rotated_poly(pol, robot_pt, w, l, x, y);
162 /* don't care about polygons further than this distance for escape */
163 #define ESCAPE_POLY_THRES 1000
165 /* don't reduce opp if opp is too far */
166 #define REDUCE_POLY_THRES 600
168 /* has to be longer than any poly */
169 #define ESCAPE_VECT_LEN 3000
172 * Go in playground, loop until out of poly. The argument robot_pt is
173 * the pointer to the current position of the robot.
174 * Return 0 if there was nothing to do.
175 * Return 1 if we had to move. In this case, update the theorical
176 * position of the robot in robot_pt.
178 static int8_t go_in_area(point_t *robot_pt)
180 point_t poly_pts_area[4];
182 point_t disc_pt, dst_pt;
187 /* Go in playground */
188 if (!is_in_boundingbox(robot_pt)){
189 NOTICE(E_USER_STRAT, "not in playground %"PRIi32", %"PRIi32"",
190 robot_pt->x, robot_pt->y);
193 poly_area.pts = poly_pts_area;
194 poly_pts_area[0].x = strat_infos.area_bbox.x1;
195 poly_pts_area[0].y = strat_infos.area_bbox.y1;
197 poly_pts_area[1].x = strat_infos.area_bbox.x2;
198 poly_pts_area[1].y = strat_infos.area_bbox.y1;
200 poly_pts_area[2].x = strat_infos.area_bbox.x2;
201 poly_pts_area[2].y = strat_infos.area_bbox.y2;
203 poly_pts_area[3].x = strat_infos.area_bbox.x1;
204 poly_pts_area[3].y = strat_infos.area_bbox.y2;
206 is_crossing_poly(*robot_pt, disc_pt, &dst_pt, &poly_area);
207 NOTICE(E_USER_STRAT, "pt dst %"PRIi32", %"PRIi32"", dst_pt.x, dst_pt.y);
209 strat_goto_xy_force(dst_pt.x, dst_pt.y);
211 robot_pt->x = dst_pt.x;
212 robot_pt->y = dst_pt.y;
214 NOTICE(E_USER_STRAT, "GOTO %"PRIi32",%"PRIi32"",
225 * Escape from polygons if needed.
226 * robot_pt is the current position of the robot, it will be
229 static int8_t escape_from_poly(point_t *robot_pt,
231 int16_t opp_x, int16_t opp_y,
232 int16_t opp_w, int16_t opp_l,
235 uint8_t in_disc = 0, in_opp = 0;
236 double escape_dx = 0, escape_dy = 0;
237 double disc_dx = 0, disc_dy = 0;
238 double opp_dx = 0, opp_dy = 0;
240 point_t opp_pt, disc_pt, dst_pt;
241 point_t intersect_disc_pt, intersect_opp_pt;
248 /* escape from other poly if necessary */
249 if (is_in_poly(robot_pt, pol_disc) == 1)
251 if (is_in_poly(robot_pt, pol_opp) == 1)
254 if (in_disc == 0 && in_opp == 0) {
255 NOTICE(E_USER_STRAT, "no need to escape");
259 NOTICE(E_USER_STRAT, "in_disc=%d, in_opp=%d", in_disc, in_opp);
261 /* process escape vector */
263 if (distance_between(robot_pt->x, robot_pt->y, DISC_X, DISC_Y) < ESCAPE_POLY_THRES) {
264 disc_dx = robot_pt->x - DISC_X;
265 disc_dy = robot_pt->y - DISC_Y;
266 NOTICE(E_USER_STRAT, " robot is near disc: vect=%2.2f,%2.2f",
268 len = norm(disc_dx, disc_dy);
277 escape_dx += disc_dx;
278 escape_dy += disc_dy;
281 if (distance_between(robot_pt->x, robot_pt->y, opp_x, opp_y) < ESCAPE_POLY_THRES) {
282 opp_dx = robot_pt->x - opp_x;
283 opp_dy = robot_pt->y - opp_y;
284 NOTICE(E_USER_STRAT, " robot is near opp: vect=%2.2f,%2.2f",
286 len = norm(opp_dx, opp_dy);
299 /* normalize escape vector */
300 len = norm(escape_dx, escape_dy);
306 if (pol_disc != NULL) {
311 else if (pol_opp != NULL) {
316 else { /* should not happen */
322 NOTICE(E_USER_STRAT, " escape vect = %2.2f,%2.2f",
323 escape_dx, escape_dy);
325 /* process the correct len of escape vector */
327 dst_pt.x = robot_pt->x + escape_dx * ESCAPE_VECT_LEN;
328 dst_pt.y = robot_pt->y + escape_dy * ESCAPE_VECT_LEN;
330 NOTICE(E_USER_STRAT, "robot pt %"PRIi32" %"PRIi32,
331 robot_pt->x, robot_pt->y);
332 NOTICE(E_USER_STRAT, "dst point %"PRIi32",%"PRIi32,
336 if (is_crossing_poly(*robot_pt, dst_pt, &intersect_disc_pt,
338 /* we add 2 mm to be sure we are out of th polygon */
339 dst_pt.x = intersect_disc_pt.x + escape_dx * 2;
340 dst_pt.y = intersect_disc_pt.y + escape_dy * 2;
341 if (is_point_in_poly(pol_opp, dst_pt.x, dst_pt.y) != 1) {
343 if (!is_in_boundingbox(&dst_pt))
346 NOTICE(E_USER_STRAT, "GOTO %"PRIi32",%"PRIi32"",
349 strat_goto_xy_force(dst_pt.x, dst_pt.y);
351 robot_pt->x = dst_pt.x;
352 robot_pt->y = dst_pt.y;
360 if (is_crossing_poly(*robot_pt, dst_pt, &intersect_opp_pt,
362 /* we add 2 cm to be sure we are out of th polygon */
363 dst_pt.x = intersect_opp_pt.x + escape_dx * 2;
364 dst_pt.y = intersect_opp_pt.y + escape_dy * 2;
366 if (is_point_in_poly(pol_disc, dst_pt.x, dst_pt.y) != 1) {
368 if (!is_in_boundingbox(&dst_pt))
371 NOTICE(E_USER_STRAT, "GOTO %"PRIi32",%"PRIi32"",
374 strat_goto_xy_force(dst_pt.x, dst_pt.y);
376 robot_pt->x = dst_pt.x;
377 robot_pt->y = dst_pt.y;
384 /* should not happen */
389 static int8_t __goto_and_avoid(int16_t x, int16_t y,
390 uint8_t flags_intermediate,
396 poly_t *pol_disc, *pol_opp;
398 int16_t opp_w, opp_l, opp_x, opp_y;
399 point_t p_dst, robot_pt;
401 DEBUG(E_USER_STRAT, "%s(%d,%d) flags_i=%x flags_f=%x forw=%d",
402 __FUNCTION__, x, y, flags_intermediate, flags_final, forward);
405 get_opponent_xy(&opp_x, &opp_y);
409 robot_pt.x = position_get_x_s16(&mainboard.pos);
410 robot_pt.y = position_get_y_s16(&mainboard.pos);
413 pol_disc = oa_new_poly(5);
414 set_central_disc_poly(pol_disc, &robot_pt);
415 pol_opp = oa_new_poly(4);
416 set_opponent_poly(pol_opp, &robot_pt, O_WIDTH, O_LENGTH);
418 /* If we are not in the limited area, try to go in it. */
419 ret = go_in_area(&robot_pt);
421 /* check that destination is valid */
424 if (!is_in_boundingbox(&p_dst)) {
425 NOTICE(E_USER_STRAT, " dst is not in playground");
428 if (is_point_in_poly(pol_disc, x, y)) {
429 NOTICE(E_USER_STRAT, " dst is in disc");
432 if (is_point_in_poly(pol_opp, x, y)) {
433 NOTICE(E_USER_STRAT, " dst is in opp");
437 /* now start to avoid */
438 while (opp_w && opp_l) {
440 /* robot_pt is not updated if it fails */
441 ret = escape_from_poly(&robot_pt,
442 pol_disc, opp_x, opp_y,
443 opp_w, opp_l, pol_opp);
446 oa_start_end_points(robot_pt.x, robot_pt.y, x, y);
453 if (distance_between(robot_pt.x, robot_pt.y, opp_x, opp_y) < REDUCE_POLY_THRES ) {
459 NOTICE(E_USER_STRAT, "oa_process() returned %d", len);
463 NOTICE(E_USER_STRAT, "reducing opponent %d %d", opp_w, opp_l);
464 set_opponent_poly(pol_opp, &robot_pt, opp_w, opp_l);
468 for (i=0 ; i<len ; i++) {
469 DEBUG(E_USER_STRAT, "With avoidance %d: x=%"PRIi32" y=%"PRIi32"", i, p->x, p->y);
472 trajectory_goto_forward_xy_abs(&mainboard.traj, p->x, p->y);
474 trajectory_goto_backward_xy_abs(&mainboard.traj, p->x, p->y);
476 /* no END_NEAR for the last point */
478 ret = wait_traj_end(flags_final);
480 ret = wait_traj_end(flags_intermediate);
482 if (ret == END_BLOCKING) {
483 DEBUG(E_USER_STRAT, "Retry avoidance %s(%d,%d)",
487 else if (ret == END_OBSTACLE) {
488 /* brake and wait the speed to be slow */
489 DEBUG(E_USER_STRAT, "Retry avoidance %s(%d,%d)",
493 /* else if it is not END_TRAJ or END_NEAR, return */
494 else if (!TRAJ_SUCCESS(ret)) {
503 /* go forward to a x,y point. use current speed for that */
504 uint8_t goto_and_avoid_forward(int16_t x, int16_t y, uint8_t flags_intermediate,
507 return __goto_and_avoid(x, y, flags_intermediate, flags_final, 1);
510 /* go backward to a x,y point. use current speed for that */
511 uint8_t goto_and_avoid_backward(int16_t x, int16_t y, uint8_t flags_intermediate,
514 return __goto_and_avoid(x, y, flags_intermediate, flags_final, 0);
517 /* go to a x,y point. prefer backward but go forward if the point is
518 * near and in front of us */
519 uint8_t goto_and_avoid(int16_t x, int16_t y, uint8_t flags_intermediate,
523 abs_xy_to_rel_da(x, y, &d, &a);
525 if (d < 300 && a < RAD(90) && a > RAD(-90))
526 return __goto_and_avoid(x, y, flags_intermediate,
529 return __goto_and_avoid(x, y, flags_intermediate,