Commit from zer0 on branch b_zer0 (2008-06-01 22:36 CEST) =================================
Only add comments. Signed-off by serpilliere ! aversive modules/devices/robot/obstacle_avoidance/obstacle_avoidance.h 1.1.2.4 aversive modules/devices/robot/obstacle_avoidance/obstacle_avoidance.c 1.1.2.5 ====================================================================== aversive/modules/devices/robot/obstacle_avoidance/obstacle_avoidance.h (1.1.2.3 -> 1.1.2.4) ====================================================================== @@ -15,10 +15,38 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Revision : $Id: obstacle_avoidance.h,v 1.1.2.3 2008-04-27 12:59:46 zer0 Exp $ + * Revision : $Id: obstacle_avoidance.h,v 1.1.2.4 2008-06-01 20:36:30 zer0 Exp $ * - * Fabrice DESCLAUX <[EMAIL PROTECTED]> - * Olivier MATZ <[EMAIL PROTECTED]> + * Main code and algorithm: Fabrice DESCLAUX <[EMAIL PROTECTED]> + * Integration in Aversive: Olivier MATZ <[EMAIL PROTECTED]> + */ + +/* + * The algorithm is based on the "visible point" algorithm. + * There are 3 inputs: + * - the play ground (basically the table, here a rectangle) + * - the objects to avoid, represented by polygones + * - start/stop points (A, B) + * + * The algorithm will first find every ray formed by 2 points that can + * "see" each others. Basically, if a polygon is between two points, + * they cannot see each others. A side of a polygon is composed by 2 + * points that can se each others. + * + * From all these rays, we can create a graph. We affect for each ray + * a weight with its own length. + * + * The algorithm executes Dijkstra to find the shortest path to go + * from A to B. + */ + +/* + * As we run on 4Ko ram uC, we have static structures arrays to store: + * - MAX_POLY => represent the maximum polygons to avoid in the area. + * - MAX_PTS => maximize the sum of every polygons vertices. + * - MAX_RAYS => maximum number of rays. + * - MAX_CHKPOINTS => maximum accepted checkpoints in the resulting path. + * - PLAYGROUND XXX => dimensions of the playground. */ /* XXX this should be set in obstacle_avoidance_config.h !! */ @@ -42,6 +70,8 @@ /* used for dijkstra */ uint8_t p; uint8_t pt; + + /* Used to determine if the destination point is reachable */ uint8_t valid; } oa_ext_point_t; @@ -52,6 +82,12 @@ int16_t y; } oa_point_t; +/* A line is represented by the equation: + * a*x + b*y + c = 0 + * + * This is better than classic a*x + b = y : + * here we can handle vertical (a*x + 0*y + c = 0) + * and horizontal lines (0*x + b*y + c = 0) */ typedef struct _line { int32_t a; int32_t b; @@ -64,7 +100,41 @@ } oa_poly_t; +struct obstacle_avoidance { + oa_poly_t polys[MAX_POLY]; /* tab of polygons (obstacles) */ + oa_ext_point_t points[MAX_PTS]; /* tab of points, referenced by polys */ + + uint8_t ray_n; + uint8_t cur_poly_idx; + uint8_t cur_pt_idx; + + uint16_t weight[MAX_RAYS]; + union { + uint8_t rays[MAX_RAYS*2]; + oa_point_t res[MAX_CHKPOINTS]; + } u; +}; +/* To save memory space here is the moemory representation of + * polygons/points: + * + * We have an array of points (oa_ext_point_t points): + * _____ _____ _____ _____ _____ _____ _____ _____ _____ + * | | | | | | | | | | + * | p0 | p1 | p0 | p1 | p2 | p3 | p0 | p1 | p2 | + * |_____|_____|_____|_____|_____|_____|_____|_____|_____| + * + * + * ^ ^ ^ + * | | | + * -polygon 0 -polygon 1 -polygon 2 + * -2 vertices -4 vertices -3 vertices + * + * + * And each polygon is represented by the sub array starting with the + * point represented by oa_ext_point_t * pts and composed of uint8_t l; + * (in the oa_poly_t structure) + */ /** Init the oa structure */ void oa_init(void); ====================================================================== aversive/modules/devices/robot/obstacle_avoidance/obstacle_avoidance.c (1.1.2.4 -> 1.1.2.5) ====================================================================== @@ -15,10 +15,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Revision : $Id: obstacle_avoidance.c,v 1.1.2.4 2008-05-09 08:26:47 zer0 Exp $ + * Revision : $Id: obstacle_avoidance.c,v 1.1.2.5 2008-06-01 20:36:30 zer0 Exp $ * - * Fabrice DESCLAUX <[EMAIL PROTECTED]> - * Olivier MATZ <[EMAIL PROTECTED]> + * Main code and algorithm: Fabrice DESCLAUX <[EMAIL PROTECTED]> + * Integration in Aversive: Olivier MATZ <[EMAIL PROTECTED]> */ #include <aversive.h> @@ -33,24 +33,12 @@ #define debug_printf(args...) -struct obstacle_avoidance { - oa_poly_t polys[MAX_POLY]; /* tab of polygons (obstacles) */ - oa_ext_point_t points[MAX_PTS]; /* tab of points, referenced by polys */ - - uint8_t ray_n; - uint8_t cur_poly_idx; - uint8_t cur_pt_idx; - - uint16_t weight[MAX_RAYS]; - union { - uint8_t rays[MAX_RAYS*2]; - oa_point_t res[MAX_CHKPOINTS]; - } u; -}; static struct obstacle_avoidance oa; -/** Init the oa structure */ +/** Init the oa structure. Note: In the algorithm, the first polygon + * is a dummy one, and is used to represent the START and END points + * (so it has 2 vertices) */ void oa_init(void) { memset(&oa, 0, sizeof(oa)); @@ -70,6 +58,13 @@ /* we always use the first 2 points of the table for start and end */ oa.points[0].x = en_x; oa.points[0].y = en_y; + + /* Each point processed by Dijkstra is marked as valid. If we + * have unreachable points (out of playground or points inside + * polygons) Disjkstra won't mark them as valid. At the end of + * the algorithm, if the destination point is not marked as + * valid, there's no valid path to reach it. */ + oa.points[0].valid = 0; /* the real dest is the start point for the algorithm */ oa.points[0].weight = 1; @@ -173,7 +168,17 @@ #define MAX_COEF 5000 -/* convert 2 points to a line */ + +/* Convert 2 points to a line. + * As we are working with intergers, we need to take care with + * coefficient of line equation: + * a*x + b*y + c = 0 can be represented by: + * 3*a*x + 3*b*y + 3*c = 0 + * + * So we try here to reduce coef in order to avoid overflow for + * future points calculations. You have to set MAX_COEF in order to + * have a precise line equation, but to avoid overflow when replacing + * (x, y) with points in the area. */ void pts2line(const oa_ext_point_t *p1, const oa_ext_point_t *p2, oa_line_t *l) { @@ -195,6 +200,9 @@ * 0 dont cross * 1 cross * 2 parallel crossing + * + * p argument is the crossing point coordinates (dummy for 0 or 2 + * result) */ uint8_t intersect_line(const oa_line_t *l1, const oa_line_t *l2, oa_ext_point_t *p) @@ -253,6 +261,9 @@ * 1 cross * 2 cross on point * 3 parallel and one point in + * + * p argument is the crossing point coordinates (dummy for 0 1 or 3 + * result) */ uint8_t intersect_segment(const oa_ext_point_t *s1, const oa_ext_point_t *s2, @@ -313,10 +324,10 @@ } -/* test if a point is in a polygon (including) +/* Test if a point is in a polygon (including edges) * 0 not inside * 1 inside - * 2 on bord + * 2 on edge */ static uint8_t is_in_poly(const oa_ext_point_t *p, oa_poly_t *pol) @@ -355,11 +366,12 @@ return is_in_poly(&p, pol); } -/* is segment crossing polygon? (including) - * 0 no cross +/* Is segment crossing polygon? (including edges) + * 0 don't cross * 1 cross - * 2 on side - * 3 touch out + * 2 on a side + * 3 touch out (a segment boundary is on a polygon edge, + * and the second segment boundary is out of the polygon) */ uint8_t is_crossing_poly(oa_ext_point_t p1, oa_ext_point_t p2, oa_poly_t *pol) @@ -433,6 +445,22 @@ (pt).y >= PLAYGROUND_Y_MIN && (pt).y<=PLAYGROUND_Y_MAX ) +/* Giving the list of poygons, compute the graph of "visibility rays". + * This rays array is composed of indexes representing 2 polygon + * vertices that can "see" each others: + * + * i : the first polygon number in the input polygon list + * i+1: the vertex index of this polygon (vertex 1) + * i+2: the second polygon number in the input polygon list + * i+3: the vertex index of this polygon (vertex 2) + * + * Here, vertex 1 can "see" vertex 2 in our visibility graph + * + * As the first polygon is not a real polygon but the start/stop + * point, the polygon is NOT an ocluding polygon (but its vertices + * are used to compute visibility to start/stop points) + */ + uint8_t calc_rays(oa_poly_t *polys, uint8_t npolys, uint8_t *rays) { @@ -444,7 +472,10 @@ /* !\\first poly is the start stop point */ - /* 1: calc inner polygon rays */ + /* 1: calc inner polygon rays + * compute for each polygon edges, if the vertices can see each others + * (usefull if interlaced polygons) + */ for (i=0; i<npolys; i++) { debug_printf("%d/%d\n", i, npolys); @@ -483,8 +514,10 @@ } - /* 2: calc inter polygon rays */ - /* for all poly */ + /* 2: calc inter polygon rays. + * Visibility of inter-polygon vertices.*/ + + /* For all poly */ for (i=0; i<npolys-1; i++) { for (pt1=0;pt1<polys[i].l;pt1++) { @@ -506,7 +539,7 @@ break; } } - /* if not crossed */ + /* if not crossed, we found a vilisity ray */ if (is_ok) { rays[ray_n++] = i; rays[ray_n++] = pt1; @@ -522,7 +555,12 @@ return ray_n; } - +/* Compute the weight of every rays: the length of the rays is used + * here. + * + * Note the +1 is a little hack to introduce a preference between to + * possiblity path: If we have 3 checpoint aligned in a path (say A, + * B, C) the algorithm will prefer (A, C) instead of (A, B, C) */ void calc_rays_weight(oa_poly_t *polys, uint8_t npolys, uint8_t *rays, uint8_t ray_n, uint16_t *weight) @@ -534,6 +572,23 @@ } } + +/* Iterative Dijkstra algorithm: The valid filed is used to determine if: + * 1: this point has been visited, his weight is correct. + * 2: the point must be visited. + * + * The algorithm does: find a point that must be visited (2) update + * his weight, mark it as (1) and update all his neightbours has 2. + * + * The algorithm ends when no (2) points are found + * + * A point with weight 0 is a point that has not been visited (so + * weight is not affected yet); This explain why first point must have + * a start weight different than 0. + * + * When the algo finds a shorter path to reach a point B from point A, + * it will store in (p, pt) the parent point. This is important to + * remenber and extract the solution path. */ void dijkstra(uint8_t start_p, uint8_t start) { @@ -555,7 +610,22 @@ if (oa.polys[start_p].pts[start].valid != 2) continue; add = -2; + + /* For all points that must be + * visited, we look for rays that + * start or stop at this point. As + * ray array is (poly_num, point_num) + * we wtep 2 by 2. */ for (i=0 ; i<oa.ray_n ; i+=2) { + + /* If index is even in the + * aray, we have a start point + * ray, so connected point is + * i+2; + * + * If index is odd, we are in stop + * point and ray start point is at + * i-2 pos */ add = -add; if (start_p == oa.u.rays[i] && start == oa.u.rays[i+1]) { @@ -619,6 +689,7 @@ uint8_t ret; uint8_t i; + /* First we compute the visibility graph */ ret = calc_rays(oa.polys, oa.cur_poly_idx, oa.u.rays); DEBUG(E_OA, "nb_rays = %d", ret); @@ -628,6 +699,7 @@ oa.u.rays[i+2], oa.u.rays[i+3]); } + /* Then we affect the rays lengths to their weights */ calc_rays_weight(oa.polys, oa.cur_poly_idx, oa.u.rays, ret, oa.weight); @@ -641,10 +713,13 @@ oa.weight[i/4]); } - + /* We aplly dijkstra on the visibility graph from the start + * point (point 0 of the polygon 0) */ oa.ray_n = ret; DEBUG(E_OA, "dijkstra ray_n = %d", ret); dijkstra(0, 0); + /* As dijkstra sets the parent points in the resulting graph, + * we can backtrack the solution path. */ return get_path(oa.polys, oa.u.rays); } _______________________________________________ Avr-list mailing list Avr-list@droids-corp.org CVSWEB : http://cvsweb.droids-corp.org/cgi-bin/viewcvs.cgi/aversive WIKI : http://wiki.droids-corp.org/index.php/Aversive DOXYGEN : http://zer0.droids-corp.org/doxygen_aversive/html/ BUGZILLA : http://bugzilla.droids-corp.org COMMIT LOGS : http://zer0.droids-corp.org/aversive_commitlog