00001
00002
00003
00004
00005
00006
00007
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
00055 while ((ch = getopt(argc, argv, "ghrt")) != -1) {
00056 switch(ch) {
00057
00058 case 'g': option.opt_flag |= OPT_GTK_TEST;
00059 test_animation(argc, argv);
00060 break;
00061
00062 case 'h': print_usage(); break;
00063
00064 case 'r': testrand(100); exit(0);
00065 break;
00066
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
00078
00079
00083 void init_robot(struct mcl_model *mcl)
00084 {
00085 struct mcl_particle *robot;
00086
00087
00088
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
00106 mcl->gen_dnoise = 0.99;
00107 mcl->gen_anoise = DEGREES(10);
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;
00115
00116
00117 mcl->count = 5000;
00118 mcl->parts = (struct mcl_particle *)
00119 malloc(sizeof(struct mcl_particle)*mcl->count);
00120
00121
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
00130 mcl->cycle = 0;
00131 mcl->noisecycle = 0;
00132
00133
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
00153 mcl->move(mcl, dx, dy, dangle);
00154
00155
00156
00157
00158
00159
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
00165
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
00179
00180
00181
00182
00183
00184
00185
00186
00187 void quit ()
00188 {
00189 gtk_exit (0);
00190 }
00191
00195
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
00208 while (pixmaps[i].xpm_filename) {
00209
00210 pixmaps[i].pixmap = gdk_pixmap_create_from_xpm(widget->window,
00211 NULL, NULL, pixmaps[i].xpm_filename);
00212 i++;
00213 }
00214
00215
00216
00217
00218
00219 pixmaps->seq_count = i;
00220 }
00221
00225 void load_scene_pixmap(GtkWidget *widget)
00226 {
00227
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
00242 case 65361:
00243 move(&mcl, -2.0, 0.0, 0.0);
00244 break;
00245
00246 case 65363:
00247 move(&mcl, 2.0, 0.0, 0.0);
00248 break;
00249
00250 case 65362:
00251 move(&mcl, 0.0, 2.0, 0.0);
00252 break;
00253
00254 case 65364:
00255 move(&mcl, 0.0, -2.0, 0.0);
00256 break;
00257
00258 case 65293:
00259 init_mcl(&mcl);
00260 break;
00261
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
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
00291 if (state & GDK_BUTTON3_MASK) {
00292 robot->x = (int)(x*FWIDTH/632);
00293 robot->y = (int)(FHEIGHT-(y*FHEIGHT/452));
00294
00295 } else {
00296 mcl.cycle++;
00297 printf("cycle = %d\n", mcl.cycle);
00298
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
00336 if (xpm_scene) {
00337 gdk_pixmap_unref (xpm_scene);
00338 }
00339
00340
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
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
00378 (*repaint_objects)();
00379
00380
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
00387 gtk_widget_draw (drawing_area, &update_rect);
00388 }
00389
00393 void test_repaint()
00394 {
00395 int i;
00396
00397
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
00417 gtk_init (&argc, &argv);
00418
00419
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
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
00456 gtk_timeout_add (SCENE_REFRESH, repaint, drawing_area);
00457 repaint_objects = repaint_func;
00458
00459
00460 load_scene_pixmap(window);
00461
00462
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
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
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
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
00538
00539
00543 void initdata()
00544 {
00545
00546 pthread_mutex_init(&mcl_mutex, NULL);
00547
00548
00549 mcl.width = FWIDTH;
00550 mcl.height = FHEIGHT;
00551
00552
00553 init_robot(&mcl);
00554 init_mcl(&mcl);
00555
00556
00557
00558
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
00581 parseopt(argc, argv);
00582
00583
00584 initdata();
00585
00586 if (!(option.opt_flag & OPT_TEXT_MODE)) {
00587
00588 init_animation(argc, argv, scene_repaint);
00589 }
00590
00591
00592 destroydata();
00593
00594 return 0;
00595 }