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
[email protected]
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