mcl.c

00001 /*
00002  * @(#)mcl.c       07/04/06
00003  * 
00004  * Description  : A simple implementation of MCL.
00005  *                The Monte Carlo Localization algorithm for mobile 
00006  *                robot navigation.
00007  *
00008  * Inspired by articles and codes from:
00009  *      http://homepages.inf.ed.ac.uk
00010  *      http://www.robotika.cz
00011  *
00012  * License      : GNU GPL v.2
00013  * Author       : Tran Duy Khanh (www.tran.cz)
00014  */
00015 
00016 #include <stdlib.h>
00017 #include <math.h>
00018 #include <robomath.h>
00019 #include <string.h>
00020 #include "mcl.h"
00021 
00034 void mcl_move(struct mcl_model *mcl, double dx, double dy, double dangle)
00035 {
00036         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00037         /*struct mcl_particle robot = *(struct mcl_particle *)mcl->system;*/
00038         int i=0;
00039         double xdiff, ydiff;
00040 
00041         /* move the particles with noises */
00042         for (i=0; i<mcl->count; i++) {
00043                 xdiff = dx*cos(parts[i].angle) + dy*sin(parts[i].angle);
00044                 ydiff = dy*cos(parts[i].angle) + dx*sin(parts[i].angle);
00045 
00046                 parts[i].x += xdiff + mcl->mov_dnoise*xdiff*gaussrand();
00047                 parts[i].y += ydiff + mcl->mov_dnoise*ydiff*gaussrand();
00048                 parts[i].angle += dangle + mcl->mov_anoise*dangle*gaussrand();
00049                 /*printf("x=%f y=%f w=%f r.x=%f r.y=%f\n", 
00050                         parts[i].x, parts[i].y, parts[i].weight,
00051                         robot.x, robot.y);*/
00052         }
00053 }
00054 
00065 void mcl_update(struct mcl_model *mcl, double x, double y, double angle)
00066 {
00067         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00068         double xdiff, ydiff, dist, avdist=0;
00069         int i;
00070 
00071         /* evaluate the weights of each particle */
00072         for (i=0; i<mcl->count; i++) {
00073                 xdiff = parts[i].x - x;
00074                 ydiff = parts[i].y - y;
00075                 dist = fabs(sqrt(xdiff*xdiff + ydiff*ydiff));
00076                 avdist += dist;
00077 
00078                 /* evaluate weights with gaussian probability density */
00079                 parts[i].weight *= evaluate_gaussian(dist, mcl->eval_sigma);
00080         }
00081 
00082         /* adjust the evaluation values */
00083         avdist /= mcl->count;
00084         if (avdist > mcl->maxavdist) {
00085                 if (mcl->noisecycle > mcl->maxnoisecycle) {
00086                         mcl->flag = MCL_RESET;
00087                         return;
00088                 } else
00089                         mcl->noisecycle++;
00090         }
00091 }
00092 
00098 void mcl_normalize(struct mcl_model *mcl)
00099 {
00100         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00101         double gain=0, w=0;
00102         int i;
00103 
00104         for (i=0; i<mcl->count; i++)
00105                 w += parts[i].weight;
00106         gain = mcl->count / w;
00107         
00108         if (gain <= 0)
00109                 return;
00110 
00111         for (i=0; i<mcl->count; i++)
00112                 parts[i].weight *= gain;
00113 }
00114 
00115 /* Compare function. Used to compare the weight of particles. Sorting is
00116  * realised with the qsort() function. */
00117 int compare(const void *a, const void *b)
00118 {
00119         return ((double)(((struct mcl_particle *)a)->weight) > 
00120                 (double)(((struct mcl_particle *)b)->weight));
00121 }
00122 
00128 void mcl_partsort(struct mcl_model *mcl)
00129 {
00130         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00131         qsort(parts, mcl->count, sizeof(struct mcl_particle), compare);
00132 }
00133 
00140 void mcl_resample(struct mcl_model *mcl)
00141 {
00142         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00143         int i, j;
00144         int i_max=0, i_min=0;
00145         size_t num = 0;
00146         int count;
00147 
00148         /* index of the particles with the lowest weight to be considered */
00149         for (i=0; i<mcl->count; i++)
00150                 if (parts[i].weight > mcl->w_min)
00151                         break;
00152         i_min = (i>0) ? i-1: i;
00153 
00154         /* index of the particles with the highest weight to be considered */
00155         for (i=0; i<mcl->count; i++)
00156                 if (parts[i].weight > mcl->w_max)
00157                         break;
00158         i_max = (i>0) ? i-1: i;
00159                 
00160         for (i=i_max; i<mcl->count; i++) {
00161                 count = (int)parts[i].weight;
00162                 count = (count > 0) ? count : 1;
00163                 parts[i].weight /= count;
00164                 for (j=num; j<num+count-1; j++)
00165                         memcpy(&parts[j], &parts[i], 
00166                                 sizeof(struct mcl_particle));
00167                 num += count-1;
00168         }
00169 
00170         for (i=num; i<i_min; i++) {
00171                 i_max--;
00172                 parts[i_max].weight /= 2;
00173                 memcpy(&parts[i], &parts[i_max], sizeof(struct mcl_particle));
00174         }
00175 }
00176 
00182 void mcl_init (struct mcl_model *mcl)
00183 {
00184         struct mcl_particle *parts = (struct mcl_particle *)mcl->parts;
00185         int i;
00186         /*int xgridsize, ygridsize;*/
00187 
00188         /*
00189         ygridsize = (int)sqrt((double)((double)mcl->count*(double)mcl->height/
00190                                 (double)mcl->width));
00191         xgridsize = (int)((double)mcl->width/(double)mcl->height*ygridsize);
00192         printf("xgridsize=%d ygridsize=%d\n", xgridsize, ygridsize);*/
00193 
00194         /* particles initialization */
00195         for (i=0; i<mcl->count; i++) {
00196                 /*xdiff = 5*cos(parts[i].angle) + 5*sin(parts[i].angle);
00197                 ydiff = 5*cos(parts[i].angle) + 5*sin(parts[i].angle);
00198 
00199                 parts[i].x = mcl->system->x + xdiff + 
00200                                 POS_STDEV_FRAC*xdiff*gaussrand();
00201                 parts[i].y = mcl->system->y + ydiff + 
00202                                 POS_STDEV_FRAC*ydiff*gaussrand();
00203                 parts[i].angle += dangle + POS_STDEV_FRAC*dangle*gaussrand();
00204                 */
00205 
00206                 /* particles with noises. Starting weight is 1, as we consider
00207                  * that any of the particles could be the right one.*/
00208                 parts[i].x = (rand()%mcl->width) * mcl->gen_dnoise;
00209                 parts[i].y = (rand()%mcl->height) * mcl->gen_dnoise;
00210                 parts[i].angle = rand() % (int)mcl->gen_anoise;
00211                 parts[i].weight = 1;
00212 
00213                 /*
00214                 parts[i].x = (i%xgridsize)*(mcl->width/xgridsize)+xgridsize/2;
00215                 parts[i].y = (i/xgridsize)*(mcl->height/ygridsize);
00216                 parts[i].angle = rand() % (int)mcl->gen_anoise;
00217                 parts[i].weight = 1;*/
00218 
00219                 /*printf("x=%f, y=%f, a=%f, w=%f\n", 
00220                         parts[i].x, parts[i].y, 
00221                         parts[i].angle, parts[i].weight);
00222                 */
00223         }                                
00224 }
00225 
00231 inline struct mcl_particle mcl_get_pos(struct mcl_model *mcl)
00232 {
00233         return (((struct mcl_particle *)mcl->parts)[mcl->count-1]);
00234 }
00235 

Generated on Thu Sep 13 11:28:28 2007 for DCE-Eurobot by  doxygen 1.5.3