mcl_gtk.c

00001 /*
00002  * @(#)mcl_gtk.c       07/04/06
00003  * 
00004  * Description  : GTK animation for a simple implementation of MCL 
00005  *                (MCL - Monte Carlo Localization).
00006  * License      : GNU GPL v.2
00007  * Author       : Tran Duy Khanh (www.tran.cz)
00008  */
00009 
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <unistd.h>
00013 #include <math.h>
00014 #include <robomath.h>
00015 #include <mcl.h>
00016 #include "mcl_gtk.h"
00017 
00018 struct mcl_model mcl;
00019 
00023 void print_usage()
00024 {
00025         fprintf(file_err, "A simple GTK demonstration of the Monte Carlo "
00026                         "algorithm,\n"
00027                         "a method used for mobile robot localization.\n"
00028                         "GNU GPL v.2, CTU FEE in Prague - Department of "
00029                         "Control Engineering\n\n");
00030         fprintf(file_err, "Usage :  [options]\n\n");
00031         fprintf(file_err, "    -g\t\tTest the GTK graphic part\n");
00032         fprintf(file_err, "    -h\t\tThis help\n");
00033         fprintf(file_err, "    -r\t\tTest the random generator\n");
00034         fprintf(file_err, "    -t\t\tText mode only\n");
00035         fprintf(file_err, "\n");
00036 
00037         exit(0);
00038 }
00039 
00046 int parseopt(int argc, char **argv)
00047 {
00048         int ch;
00049         
00050         file_out = stdout;
00051         file_err = stderr;
00052 
00053         optind = 0;
00054         /* parse the program arguments */
00055         while ((ch = getopt(argc, argv, "ghrt")) != -1) {
00056                 switch(ch) {
00057                         /* test GTK graphic part */
00058                         case 'g':       option.opt_flag |= OPT_GTK_TEST;
00059                                         test_animation(argc, argv);
00060                                         break;
00061                         /* print program usage */
00062                         case 'h':       print_usage(); break;
00063                         /* test random generator */
00064                         case 'r':       testrand(100); exit(0);
00065                                         break;
00066                         /* text output only. No GTK. */
00067                         case 't':       option.opt_flag |= OPT_TEXT_MODE;
00068                                         break;
00069                         default:        print_usage(); break;
00070                 }
00071         }
00072         
00073         return 0;
00074 }
00075 
00076 /****************************************************************************
00077  * MCL stuffs.
00078  ****************************************************************************
00079  */
00083 void init_robot(struct mcl_model *mcl)
00084 {
00085         struct mcl_particle *robot;
00086 
00087         /* the robot particle is used just to be able to move the robot on
00088          * the playground. */
00089         mcl->system = (struct mcl_particle*)
00090                         malloc(sizeof(struct mcl_particle));
00091         robot = mcl->system;
00092         robot->x = 216;
00093         robot->y = 300;
00094         robot->angle = DEGREES(0);;
00095         robot->weight = 1;
00096 }
00097 
00103 void init_mcl(struct mcl_model *mcl)
00104 {
00105         /* the noises */
00106         mcl->gen_dnoise = 0.99;         /* distance noise */
00107         mcl->gen_anoise = DEGREES(10);  /* angle noise */
00108         mcl->mov_dnoise = 1.1;
00109         mcl->mov_anoise = 2.0;
00110         mcl->w_min = 0.25;
00111         mcl->w_max = 2.0;
00112         mcl->eval_sigma = 0.5;
00113         mcl->maxavdist = 50;
00114         mcl->maxnoisecycle = 10;        /* bad cycles before reseting */
00115 
00116         /* amount of particles */
00117         mcl->count = 5000;
00118         mcl->parts = (struct mcl_particle *)
00119                         malloc(sizeof(struct mcl_particle)*mcl->count);
00120 
00121         /* phases of the MCL */
00122         mcl->init = mcl_init;
00123         mcl->move = mcl_move;
00124         mcl->update = mcl_update;
00125         mcl->normalize = mcl_normalize;
00126         mcl->sort = mcl_partsort;
00127         mcl->resample = mcl_resample;
00128 
00129         /* cycles of enumeration */
00130         mcl->cycle = 0;
00131         mcl->noisecycle = 0;
00132 
00133         /* generate particles with noises */
00134         mcl->init(mcl);
00135 }
00136 
00145 void move(struct mcl_model *mcl, double dx, double dy, double dangle)
00146 {
00147         struct mcl_particle *robot = (struct mcl_particle *)mcl->system;
00148         struct mcl_particle x;
00149 
00150         mcl->cycle++;
00151         printf("cycle = %d\n", mcl->cycle);
00152         /* move particles */
00153         mcl->move(mcl, dx, dy, dangle);
00154 
00155         /* the robot particle is used just to be able to move the robot on
00156          * the playground. In addition we use this values as the reference 
00157          * values measured by sensors. In the real world, the sensors measure
00158          * with a certain noise, but int this example we consider the 
00159          * measurements are not suffered by noises. */
00160         robot->x += dx*cos(robot->angle) + dy*sin(robot->angle);
00161         robot->y += dy*cos(robot->angle) + dx*sin(robot->angle);
00162         robot->angle += dangle;
00163 
00164         /* normally, the [x,y,angle] are values measured by sensors. In this 
00165          * example, the values are quantified as the movement without noises*/
00166         mcl->update(mcl, robot->x, robot->y, robot->angle);
00167         if (mcl->flag == MCL_RESET) {
00168                 init_mcl(mcl);
00169                 mcl->flag = MCL_RUN;
00170                 return;
00171         }
00172         mcl->normalize(mcl);
00173         mcl->sort(mcl);
00174         mcl->resample(mcl);
00175         x = mcl_get_pos(mcl);
00176         printf("estimated position: %f %f %f %f\n", x.x, x.y, x.angle, x.weight);
00177 }
00178 /* end of the MCL stuffs.
00179  ****************************************************************************/
00180 
00181 /****************************************************************************
00182  * GTK Graphic stuffs.
00183  ****************************************************************************
00184  */
00185 
00186 /* Get out of the aplication */
00187 void quit ()
00188 {
00189         gtk_exit (0);
00190 }
00191 
00195 /*void get_size (GdkPixmap *xpm, unsigned int *width, unsigned int *height)
00196 {
00197 }*/
00198 
00202 void load_pixmaps (GtkWidget *widget, struct moveable_obj *moveable, 
00203                                     struct pixmap_obj *pixmaps)
00204 {
00205         int i = 0;
00206         
00207         /* Get every sequence */
00208         while (pixmaps[i].xpm_filename) {
00209                 /* Convert xpm data to pixmap & mask */
00210                 pixmaps[i].pixmap = gdk_pixmap_create_from_xpm(widget->window, 
00211                                         NULL, NULL, pixmaps[i].xpm_filename);
00212                 i++;
00213         }
00214 
00215         /* Get sprite height and width */
00216         /* get_size(pixmaps[0].pixmap, &pixmaps[0].width, &pixmaps[0].height); */
00217         
00218         /* Initialize sprite information */
00219         pixmaps->seq_count = i;
00220 }
00221 
00225 void load_scene_pixmap(GtkWidget *widget)
00226 {
00227         /* load background, robot, sample pixmaps */
00228         load_pixmaps(widget, moveable, xpm_background);
00229         load_pixmaps(widget, moveable, xpm_robot);
00230         load_pixmaps(widget, moveable, xpm_sample);
00231 }
00232 
00236 static gboolean key_event(GtkWidget *widget, GdkEventKey *event)
00237 {
00238         GdkModifierType state;
00239 
00240         switch (event->keyval) {
00241                 /* left */
00242                 case 65361:
00243                         move(&mcl, -2.0, 0.0, 0.0);
00244                         break;
00245                 /* right */
00246                 case 65363:
00247                         move(&mcl, 2.0, 0.0, 0.0);
00248                         break;
00249                 /* up */
00250                 case 65362:
00251                         move(&mcl, 0.0, 2.0, 0.0);
00252                         break;
00253                 /* down */
00254                 case 65364:
00255                         move(&mcl, 0.0, -2.0, 0.0);
00256                         break;
00257                 /* enter - reinitialization */
00258                 case 65293:
00259                         init_mcl(&mcl);
00260                         break;
00261                 /* quit */
00262                 case 'q':
00263                 case 'Q':
00264                 case 65307:
00265                         quit();
00266         }
00267         
00268         return TRUE;
00269 }
00270 
00274 static gboolean button_event(GtkWidget *widget, GdkEventMotion *event)
00275 {
00276         int x, y;
00277         GdkModifierType state;
00278         struct mcl_particle *robot = (struct mcl_particle *)mcl.system;
00279 
00280         /* get the position mouse state */
00281         if (event->is_hint) 
00282                 gdk_window_get_pointer (event->window, &x, &y, &state);
00283         else {
00284                 x = event->x;
00285                 y = event->y;
00286                 state = event->state;
00287         }
00288                 printf("x=%d y=%d\n", x, y);
00289 
00290         /* replace robot to another position */
00291         if (state & GDK_BUTTON3_MASK) {
00292                 robot->x = (int)(x*FWIDTH/632);
00293                 robot->y = (int)(FHEIGHT-(y*FHEIGHT/452));
00294         /* move particles and reset if needed */
00295         } else {
00296                 mcl.cycle++;
00297                 printf("cycle = %d\n", mcl.cycle);
00298                 /* move particles */
00299                 mcl.move(&mcl, 2.0, 2.0, 0.0);
00300                 mcl.update(&mcl, x-BORDER, y-BORDER, 0);
00301                 if (mcl.flag == MCL_RESET) {
00302                         init_mcl(&mcl);
00303                         mcl.flag = MCL_RUN;
00304                         return TRUE;
00305                 }
00306                 mcl.normalize(&mcl);
00307                 mcl.sort(&mcl);
00308                 mcl.resample(&mcl);
00309         }
00310         
00311         return TRUE;
00312 }
00313 
00317 static gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event)
00318 {
00319         int x, y;
00320         GdkModifierType state;
00321 
00322         if (event->is_hint) 
00323                 gdk_window_get_pointer (event->window, &x, &y, &state);
00324         else {
00325                 x = event->x;
00326                 y = event->y;
00327                 state = event->state;
00328         }
00329   
00330         return TRUE;
00331 }
00332 
00333 static gint configure_event (GtkWidget *widget, GdkEventConfigure *event)
00334 {
00335         /* Free background if we created it */
00336         if (xpm_scene) {
00337                 gdk_pixmap_unref (xpm_scene);
00338         } 
00339 
00340         /* Create a new pixmap with new size */
00341         xpm_scene = gdk_pixmap_new (widget->window,
00342                         widget->allocation.width,
00343                         widget->allocation.height,
00344                         -1);
00345         
00346         return TRUE;
00347 }
00348 
00352 gint expose_event (GtkWidget *widget, GdkEventExpose *event)
00353 {
00354         int i;
00355         
00356         /* Copy pixmap to the window */
00357         gdk_draw_pixmap (widget->window,
00358                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
00359                 xpm_scene,
00360                 event->area.x, event->area.y,
00361                 event->area.x, event->area.y,
00362                 event->area.width, event->area.height);
00363         
00364         return FALSE;
00365 }
00366 
00367 void (*repaint_objects)();
00368 
00372 gint repaint (gpointer data)
00373 {
00374         GtkWidget  *drawing_area = (GtkWidget *)data;
00375         GdkRectangle update_rect;
00376         
00377         /*test_repaint();*/
00378         (*repaint_objects)();
00379         
00380         /* The whole screen needs to be updated */
00381         update_rect.x = 0;
00382         update_rect.y = 0;
00383         update_rect.width = drawing_area->allocation.width;
00384         update_rect.height = drawing_area->allocation.height;
00385         
00386         /* So update it */
00387         gtk_widget_draw (drawing_area, &update_rect);
00388 }
00389 
00393 void test_repaint()
00394 {
00395         int i;
00396         
00397         /* clear pixmap (background image) */
00398         gdk_draw_drawable (xpm_scene,
00399                 drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)],
00400                 xpm_background[0].pixmap,
00401                 0, 0,
00402                 0, 0,
00403                 drawing_area->allocation.width,
00404                 drawing_area->allocation.height);
00405 }
00406 
00414 void init_animation(int argc, char *argv[], void (*repaint_func)())
00415 {
00416         /* Initialize GTK */
00417         gtk_init (&argc, &argv);
00418         
00419         /* Create the top level window */
00420         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00421         
00422         gtk_signal_connect (GTK_OBJECT (window), "destroy",
00423                                 GTK_SIGNAL_FUNC (quit), NULL);
00424         
00425         /* Create the drawing area */
00426         drawing_area = gtk_drawing_area_new ();
00427         gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 
00428                                 xpm_background[0].width, 
00429                                 xpm_background[0].height);
00430         gtk_container_add (GTK_CONTAINER (window), drawing_area);
00431 
00432         gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
00433                                 (GtkSignalFunc) expose_event, NULL);
00434         gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
00435                                 (GtkSignalFunc) configure_event, NULL);
00436         gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
00437                                 (GtkSignalFunc) motion_notify_event, NULL);
00438         gtk_signal_connect (GTK_OBJECT(drawing_area),"button_press_event",
00439                                 (GtkSignalFunc) button_event, NULL);
00440         gtk_signal_connect (GTK_OBJECT(drawing_area),"button_release_event",
00441                                 (GtkSignalFunc) button_event, NULL);
00442         gtk_signal_connect (GTK_OBJECT(window),"key_press_event",
00443                                 (GtkSignalFunc) key_event, NULL);
00444 
00445 
00446         gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
00447                                 | GDK_LEAVE_NOTIFY_MASK
00448                                 | GDK_BUTTON_PRESS_MASK
00449                                 | GDK_POINTER_MOTION_MASK
00450                                 | GDK_POINTER_MOTION_HINT_MASK);
00451 
00452         gtk_widget_show(drawing_area);
00453         gtk_widget_show(window);
00454 
00455         /* Repaint every so often */
00456         gtk_timeout_add (SCENE_REFRESH, repaint, drawing_area);
00457         repaint_objects = repaint_func;
00458         
00459         /* Load all scene pixmaps */
00460         load_scene_pixmap(window);
00461         
00462         /* Call gtk-main loop */
00463         gtk_main();
00464 }
00465 
00469 int get_color(double weight)
00470 {
00471         if (weight <= 0.005)
00472                 return 0;
00473         else if (weight <= 0.01)
00474                 return 1;
00475         else if (weight <= 0.1)
00476                 return 2;
00477         else if (weight <= 0.5)
00478                 return 3;
00479         else
00480                 return 4;
00481 }
00482 
00486 void test_animation(int argc, char *argv[])
00487 {
00488         init_animation(argc, argv, test_repaint);
00489 }
00490 
00494 void scene_repaint()
00495 {
00496         struct mcl_particle *parts = (struct mcl_particle *)mcl.parts;
00497         struct mcl_particle *robot = (struct mcl_particle *)mcl.system;
00498         int i;
00499         int x;
00500         
00501         /* clear pixmap (background image) */
00502         gdk_draw_drawable (xpm_scene,
00503                 drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)],
00504                 xpm_background[0].pixmap,
00505                 0, 0,
00506                 0, 0,
00507                 drawing_area->allocation.width,
00508                 drawing_area->allocation.height);
00509 
00510         /* draw the robot */
00511         gdk_draw_drawable (xpm_scene,
00512                 drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)],
00513                 xpm_robot[0].pixmap,
00514                 0, 0,
00515                 (int)(robot->x/FWIDTH*(632-2*BORDER)+BORDER) 
00516                                         - xpm_robot[0].height/2,
00517                 (int)((FHEIGHT-robot->y)/FHEIGHT*(452-2*BORDER)+BORDER) 
00518                                         - xpm_robot[0].width/2, 
00519                 drawing_area->allocation.width,
00520                 drawing_area->allocation.height);
00521 
00522         /* draw the particles */
00523         for (i=0; i<mcl.count; i++) {
00524                 gdk_draw_drawable (xpm_scene,
00525                         drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)],
00526                         xpm_sample[get_color(parts[i].weight)].pixmap,
00527                         0, 0,
00528                         (int)(parts[i].x/FWIDTH*(632-2*BORDER)+BORDER) 
00529                                                 - xpm_sample[0].height/2,
00530                         (int)((FHEIGHT-parts[i].y)/FHEIGHT*(452-2*BORDER)+BORDER) 
00531                                                 - xpm_sample[0].width/2, 
00532                         drawing_area->allocation.width,
00533                         drawing_area->allocation.height);
00534         }                                
00535 }
00536 
00537 /* end of the GTK stuffs.
00538  ****************************************************************************/
00539 
00543 void initdata()
00544 {
00545         /* init mutex */
00546         pthread_mutex_init(&mcl_mutex, NULL);
00547 
00548         /* MCL initialization */
00549         mcl.width = FWIDTH;
00550         mcl.height = FHEIGHT;
00551         /* the robot particle is used just to be able to move the robot on
00552          * the playground. */
00553         init_robot(&mcl);
00554         init_mcl(&mcl);
00555 
00556         /*
00557         pthread_mutex_lock(&mcl_mutex);
00558         pthread_mutex_unlock(&mcl_mutex);*/
00559 }
00560 
00564 void destroydata()
00565 {
00566         pthread_mutex_destroy(&mcl_mutex);
00567 }
00568 
00575 int main(int _argc, char **_argv)
00576 {
00577         argc = _argc;
00578         argv = _argv;
00579         
00580         /* parse program options */
00581         parseopt(argc, argv);
00582         
00583         /* data initialization */
00584         initdata();
00585 
00586         if (!(option.opt_flag & OPT_TEXT_MODE)) {
00587                 /* run animation initialization */
00588                 init_animation(argc, argv, scene_repaint);
00589         }
00590         
00591         /* destroy data (mutex, ...) */
00592         destroydata();
00593         
00594         return 0;
00595 }

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