fsmmove.cc

Go to the documentation of this file.
00001 
00007 #define FSM_MOTION
00008 #include <sys/time.h>
00009 #include <time.h>
00010 #include "fsmmove.h"
00011 #include "trgen.h"
00012 #include "balet.h"
00013 #include "robot.h"
00014 #include <pthread.h>
00015 #include <path_planner.h>
00016 #include <signal.h>
00017 #include "movehelper.h"
00018 #include <sharp.h>
00019 #include <unistd.h>
00020 #include <map.h>
00021 #include "robot_config.h"
00022 
00023 
00024 /*******************************************************************************
00025  * Parameters of Obstacle detection
00026  *******************************************************************************/
00027 
00028 #define OBS_PERIOD_WATCH        100000          
00029 #define OBS_PERIOD_BETWEEN_DET  1000000         
00030 #define OBS_CSPACE              (200/MAP_CELL_SIZE)     
00031 #define OBS_FORGET_PERIOD       100000          
00033 #define OBS_UPDATE_MAP_SPEED 15                 
00034 /*******************************************************************************
00035  * Controller thread and helper functions for that thread
00036  *******************************************************************************/
00037 
00038 
00039 //Controller gains
00040 const double k[3] =
00041         {
00042                 2,               // dx gain
00043                 2,               // dphi gain
00044                 10
00045         }
00046         ;             // dy gain
00047 #define MAX_POS_ERROR_M 0.5
00048 #define CLOSE_TO_TARGET_M 0.1
00049 #define MAX_WAIT_FOR_CLOSE_MS 2000
00050 
00051 //#define MOTION_PERIOD_NS (500/*ms*/*1000*1000)
00052 #define MOTION_PERIOD_NS (50/*ms*/*1000*1000)
00053 #define SIG_TIMER (SIGRTMIN+0)
00054 #define SIG_NEWDATA (SIGRTMIN+1)
00055 
00056 // Global varibles
00057 static pthread_t thr_trajctory_follower;
00058 static pthread_t thr_trajctory_recalc;
00059 static pthread_t thr_update_map;
00060 static struct timeval tv_start; 
00063 static Trajectory *actual_trajectory = NULL;
00064 
00065 //static Trajectory *switch_to_trajectory = NULL;
00066 //static double switch_time;
00067 
00068 // function definition
00069 static fsm_event new_goal(void);
00070 static void stop();
00071 
00072 bool actual_trajectory_reverse;
00073 pthread_mutex_t actual_trajectory_lock = PTHREAD_MUTEX_INITIALIZER;
00074 pthread_mutex_t switch_to_trajectory_lock = PTHREAD_MUTEX_INITIALIZER;
00075 
00076 // static void odometry(double l, r) {
00077 //      static double last_l, last_r;
00078 
00079 //      robot.act_pos.x = (double)ROBOT_AXIS_TO_BACK_MM/1000;
00080 //      robot.act_pos.y = ((double)PLAYGROUND_HEIGHT_MM - ROBOT_WIDTH_MM/2)/1000;
00081 //      robot.act_pos.phi = 0;
00082 
00083 //      ROBOT_LOCK(act_pos);
00084 //      ROBOT_UNLOCK(act_pos);
00085 // }
00086 
00087 void delete_actual_trajectory()
00088 {
00089         Trajectory *old;
00090         pthread_mutex_lock(&actual_trajectory_lock);
00091         old = actual_trajectory;
00092         actual_trajectory = NULL;
00093         pthread_mutex_unlock(&actual_trajectory_lock);
00094         robot_send_speed(0,0);
00095         if (old) delete(actual_trajectory);
00096 }
00097 
00099 static void notify_fsm(bool done, double error)
00100 {
00101         static bool done_sent;
00102 
00103         if (error > MAX_POS_ERROR_M) {
00104                 FSM_SIGNAL(MOTION, EV_TRAJECTORY_LOST);
00105         } else {
00106                 if (done) {
00107                         if (error < CLOSE_TO_TARGET_M) {
00108                                 FSM_SIGNAL(MOTION, EV_TRAJECTORY_DONE_AND_CLOSE);
00109                         } else if (!done_sent) {
00110                                 done_sent = true;
00111                                 FSM_SIGNAL(MOTION, EV_TRAJECTORY_DONE);
00112                         }
00113                 } else {
00114                         done_sent = false;
00115                 }
00116         }
00117 }
00118 
00131 static void *trajectory_follower(void *arg)
00132 {
00133         struct itimerspec ts;
00134         sigset_t sigset;
00135         struct sigevent sigevent;
00136         timer_t timer;
00137 
00138         ts.it_value.tv_sec = 0;
00139         ts.it_value.tv_nsec = MOTION_PERIOD_NS;
00140         ts.it_interval.tv_sec = 0;
00141         ts.it_interval.tv_nsec = MOTION_PERIOD_NS;
00142 
00143         sigemptyset(&sigset);
00144         sigaddset(&sigset, SIG_TIMER);
00145         sigaddset(&sigset, SIG_NEWDATA);
00146 
00147         pthread_sigmask(SIG_BLOCK, &sigset, (sigset_t*) NULL);
00148 
00149         sigevent.sigev_notify = SIGEV_SIGNAL;
00150         sigevent.sigev_signo = SIG_TIMER;
00151         sigevent.sigev_value.sival_int = 0;
00152 
00153         if (timer_create(CLOCK_REALTIME, &sigevent, &timer) < 0) {
00154                 perror("move: timer_create");
00155                 return NULL;
00156         }
00157 
00158         if (timer_settime(timer, 0, &ts, NULL) < 0) {
00159                 perror("move: timer_settimer");
00160                 return NULL;
00161         }
00162 
00163         while (1) {
00164                 double speeds[2];
00165                 int sig;
00166                 // Wait for start of new period or new data
00167                 sigwait(&sigset, &sig);
00168                 //DBG("signal %d ", sig - SIGRTMIN);
00169                 pthread_mutex_lock(&actual_trajectory_lock);
00170                 Trajectory *w = actual_trajectory;
00171                 if (w) {
00172                         Pos ref_pos;
00173                         bool done;
00174                         struct position_type ap;
00175                         double t;
00176                         struct timeval tv;
00177 
00178                         // Calculate reference position
00179                         gettimeofday(&tv, NULL);
00180                         t = (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
00181                         t += (tv.tv_sec - tv_start.tv_sec);
00182 
00183 
00184                         done = w->getRefPos(t, ref_pos);
00185                         pthread_mutex_unlock(&actual_trajectory_lock);
00186 
00187                         ROBOT_LOCK(act_pos);
00188 #ifdef CONFIG_OPEN_LOOP
00189                         // We don't use any feedback now. It is
00190                         // supposed that the actual position is equal
00191                         // to reference position.
00192                         robot.act_pos.x = ref_pos.x;
00193                         robot.act_pos.y = ref_pos.y;
00194                         robot.act_pos.phi = ref_pos.phi;
00195 #endif
00196                         ap = robot.act_pos;
00197 
00198                         ROBOT_UNLOCK(act_pos);
00199                         double aktPos[] = { ap.x, ap.y, ap.phi };
00200                         DBG("rx=%5.02f ry=%5.02f, rphi=%4.0f v=%-4.02f\r", ref_pos.x, ref_pos.y, ref_pos.phi/M_PI*180, ref_pos.v);
00201                         fflush(stdout);
00202                         // Call the controller
00203                         double error;
00204                         error = balet(ref_pos, aktPos, speeds, k);
00205 
00206                         notify_fsm(done, error);
00207                 } else {
00208                         pthread_mutex_unlock(&actual_trajectory_lock);
00209                         speeds[0] = 0;
00210                         speeds[1] = 0;
00211                 }
00212 
00213 
00214                 // Apply controller output
00215                 robot_send_speed(speeds[0], speeds[1]);
00216         }
00217 }
00218 
00229 static void * trajctory_recalc(void * arg)
00230 {
00231         int i,j, xcell, ycell;
00232         double val, x, y;
00233         Pos p;
00234         
00235         while (1) {
00237                 //ShmapUpdateTmpObstacles(OBS_UPDATE_MAP_SPEED);
00238                 ROBOT_LOCK(sharpsOpponent);
00239                 val = (robot.sharpsOpponent.longSharpDist1 + robot.sharpsOpponent.longSharpDist2 +
00240                        robot.sharpsOpponent.longSharpDist3)/3.0;
00241                 ROBOT_UNLOCK(sharpsOpponent);
00242                 
00243                 if ((val<0.8)){
00244                         int flag_recalc;        // This flag indicates if the path should be recalculated
00245                         int flag_goal_obst;     // This flag indicates that the goal is an obstacle
00246 
00247                         flag_recalc = 0;
00248                         flag_goal_obst = 0;
00249                         
00251                         ROBOT_LOCK(act_pos);
00252                         p.x = robot.act_pos.x;
00253                         p.y = robot.act_pos.y;
00254                         p.phi = robot.act_pos.phi;
00255                         ROBOT_UNLOCK(act_pos);
00261                         x = val*cos(p.phi) + p.x;
00262                         y = val*sin(p.phi) + p.y;
00263                         DBG("New obstacle detected at cell [%f,%f] \n", x,y);
00264                         if (ShmapIsFreePoint(x,y)){
00265                                 xcell=ShmapPoint2Cell_X(x);ycell=ShmapPoint2Cell_Y(y);
00266                                 DBG("Cell %d, %d\n", xcell, ycell);
00268                                 for (i=(xcell-OBS_CSPACE); i <= xcell+OBS_CSPACE; i++) {
00269                                         for (j=(ycell- OBS_CSPACE); j <=ycell + OBS_CSPACE; j++) {
00270                                                 switch (ShmapGetCellValue(i,j)){
00271                                                         case MAP_PATH:
00272                                                         case MAP_GOAL:
00273                                                                 flag_recalc =1;
00274                                                         case MAP_FREE:
00275                                                                 ShmapSetCellValue(i , j, MAP_NEW_OBSTACLE);
00276                                                         break;
00277                                                         case MAP_WALL:
00278                                                         case MAP_WALL_CSPACE:
00279                                                         case MAP_NEW_OBSTACLE:
00280                                                         case MAP_NEW_OBSTACLE_CSPACE:
00281                                                         case MAP_NOT_IN_MAP:
00282                                                         default:
00283                                                                 break;
00284                                                 }
00285                                         }
00286                                 }
00287 
00288                                 // Path recalculation if the goal is not an obstacle and the path should be recalc
00289                                 if (flag_goal_obst) {
00290                                         FSM_SIGNAL(MOTION, EV_MOVE_STOP);
00291                                         FSM_SIGNAL(MAIN, EV_GOAL_IS_TMP_OBSTACLE);
00292                                 } else if (flag_recalc){
00293                                         if (new_goal() == 0) DBG("Path recalc\n");
00294                                 } else {
00295                                         DBG("Not necessary to recalc the path\n");
00296                                 }
00297                         } else DBG("The detected obstacle is already in the map\n");
00298                         
00299                         //waits between detection
00300                         usleep(OBS_PERIOD_BETWEEN_DET);
00301                 }
00303                 usleep(OBS_PERIOD_WATCH);
00304         }
00305 }
00306 
00310 static void * thread_update_map(void * arg){
00311         while (1) {
00313                 ShmapUpdateTmpObstacles(OBS_UPDATE_MAP_SPEED);
00314                 usleep(OBS_FORGET_PERIOD);
00315         }
00316 }
00317 
00323 static void go(Trajectory *t)
00324 {
00325         Trajectory *old;
00326         pthread_mutex_lock(&actual_trajectory_lock);
00327         old = actual_trajectory;
00328         gettimeofday(&tv_start, NULL);
00329         actual_trajectory = t;
00330         pthread_mutex_unlock(&actual_trajectory_lock);
00331         if (old)
00332                 delete(old);
00333 }
00334 
00335 static void stop()
00336 {
00337         delete_actual_trajectory();
00338         pthread_kill(thr_trajctory_follower, SIG_NEWDATA);
00339 }
00340 
00341 
00347 static int new_goal(void)
00348 {
00349         double startx, starty, goalx, goaly, angle;
00350         PathPoint * path = NULL;
00351         PathPoint * tmp_point = NULL;
00352         
00353         struct TrajectoryConstraints tc = trajectoryConstraintsDefault;
00354         Pos start;
00355         //tc.maxv *= 2.5;
00356         //tc.maxacc *= 2.5;
00357 
00359         ROBOT_LOCK(act_pos);
00360         startx = robot.act_pos.x;
00361         starty = robot.act_pos.y;
00362         start.x = startx;
00363         start.y = starty;
00364         start.phi = robot.act_pos.phi;
00365         ROBOT_UNLOCK(act_pos);
00367         ROBOT_LOCK(goal);
00368         goalx = robot.goal.x;
00369         goaly = robot.goal.y;
00370         ROBOT_UNLOCK(goal);
00371 
00372         //DBG("Going from (%.2f, %.2f) to (%.2f, %.2f)\n", startx, starty, goalx, goaly);
00374         switch (path_planner(startx, starty, goalx, goaly, &path, &angle)) {
00375                 case 1:
00376                         break;
00377                 case PP_ERROR_MAP_NOT_INIT:
00378                         FSM_SIGNAL(MAIN, EV_MAP_NOT_INIT);
00379                         return -1;
00380                         break;
00381                 case PP_ERROR_GOAL_IS_OBSTACLE:
00382                         FSM_SIGNAL(MAIN, EV_GOAL_IS_OBSTACLE);
00383                         return -1;
00384                         break;
00385                 case PP_ERROR_GOAL_NOT_REACHABLE:
00386                         FSM_SIGNAL(MAIN, EV_GOAL_NOT_REACHABLE);
00387                         return -1;
00388                         break;
00389                 default:
00390                         break;
00391                 // shouldn't we call freePathMemory() here? No, because no memory has been allocanted for the path, path is only a pointer to NULL
00392         }
00393 
00394         bool backward = false;
00395         Trajectory *t = new Trajectory(tc, backward);
00396 
00397         // Add this  path to the trajectory.
00398         for (tmp_point = path; tmp_point!=NULL; tmp_point=tmp_point->next) {
00399                 //DBG("ADDDING POINT (%f, %f)\n", tmp_point->x, tmp_point->y);
00400                 t->addPoint(tmp_point->x, tmp_point->y);
00401         }
00402 
00403         // add the path to the robot trajectory
00404         t->finalHeading = angle; // NAN should be OK here, if not, it is error.
00405 
00406         // Free path allocated memory
00407         freePathMemory(path);
00408 
00409         if (t->prepare(start)) {
00410                 go(t);
00411         } else {
00412                 DBG("ERROR preparing trajectory\n");
00413                 delete(t);
00414                 FSM_SIGNAL(MAIN, EV_TRAJECTORY_ERROR);
00415                 return -1;
00416         }
00417 
00418         return 0;
00419 }
00420 
00421 
00429 static int new_trajectory(void)
00430 {
00431         Trajectory *t;
00432         Pos pos;
00433         ROBOT_LOCK(new_trajectory);
00434         t = (Trajectory*) robot.new_trajectory;
00435         if (t) robot.new_trajectory = NULL;
00436         else {
00437                 ROBOT_UNLOCK(new_trajectory);
00438                 DBG("No trajectory\n");
00439                 FSM_SIGNAL(MAIN, EV_TRAJECTORY_ERROR);
00440                 return -1;
00441         }
00442         ROBOT_UNLOCK(new_trajectory);
00443 
00444 
00445         ROBOT_LOCK(act_pos);
00446         pos.x = robot.act_pos.x;
00447         pos.y = robot.act_pos.y;
00448         pos.phi = robot.act_pos.phi;
00449         ROBOT_UNLOCK(act_pos);
00450 
00451         if (t->prepare(pos)) {
00452                 go(t);
00453         } else {
00454                 FSM_SIGNAL(MAIN, EV_MOTION_DONE); // FIXME: Is this correct?
00455                 return -1;
00456         }
00457         return 0;
00458 }
00459 
00460 /*******************************************************************************
00461  * The automaton
00462  *******************************************************************************/
00463 
00464 FSM_STATE_DECL(movement);
00465 FSM_STATE_DECL(close_to_target);
00466 FSM_STATE_DECL(wait_for_command);
00467 
00468 
00469 FSM_STATE(move_init)
00470 {
00471         pthread_attr_t tattr;
00472         sched_param param;
00473         int ret;
00474 
00475         if (FSM_EVENT == EV_INIT) {
00476                 actual_trajectory = NULL;
00477 
00478                 // Trajectory follower thread
00479                 pthread_attr_init (&tattr);
00480                 pthread_attr_getschedparam (&tattr, &param);
00481                 param.sched_priority = TRAJ_FOLLOWER_PRIO;
00482                 ret = pthread_attr_setschedparam (&tattr, &param);
00483                 if(ret) {
00484                         perror("pthread_attr_setschedparam");
00485                         exit(1);
00486                 }
00487                 ret = pthread_create(&thr_trajctory_follower, &tattr, trajectory_follower, NULL);
00488                 if(ret) {
00489                         perror("pthread_create");
00490                         exit(1);
00491                 }
00492                 // Thread of trajectory recalc
00493                 pthread_attr_init (&tattr);
00494                 pthread_attr_getschedparam (&tattr, &param);
00495                 param.sched_priority = TRAJ_RECALC_PRIO;
00496                 ret = pthread_attr_setschedparam (&tattr, &param);
00497                 if(ret) {
00498                         perror("pthread_attr_setschedparam");
00499                         exit(1);
00500                 }
00501                 pthread_create(&thr_trajctory_recalc, NULL, trajctory_recalc, NULL);
00502                 
00503                 // Thread update Map
00504                 pthread_attr_init (&tattr);
00505                 pthread_attr_getschedparam (&tattr, &param);
00506                 param.sched_priority = TRAJ_RECALC_PRIO;
00507                 ret = pthread_attr_setschedparam (&tattr, &param);
00508                 if(ret) {
00509                         perror("pthread_attr_setschedparam");
00510                         exit(1);
00511                 }
00512                 pthread_create(&thr_update_map, NULL, thread_update_map, NULL);
00513                 
00514                 FSM_TRANSITION(wait_for_command);
00515         }
00516 }
00517 
00518 FSM_STATE(wait_for_command)
00519 {
00520         switch (FSM_EVENT) {
00521                 case EV_STATE_ENTERED:
00522                         stop();
00523                         break;
00524                 case EV_NEW_GOAL:
00525                         if (new_goal() != 0) {
00526                                 // The event must be the return value of new_goal()
00527                                 DBG("Goal error\n");
00528                                 break;
00529                         }
00530                         FSM_TRANSITION(movement);
00531                         break;
00532                 case EV_NEW_TRAJECTORY:
00533                         if (new_trajectory() != 0) {
00534                                 break;
00535                         }
00536                         FSM_TRANSITION(movement);
00537                         break;
00538                 default:
00539                         break;
00540         }
00541 }
00542 
00543 
00544 
00545 FSM_STATE(movement)
00546 {
00547         switch (FSM_EVENT) {
00548                 case EV_TRAJECTORY_DONE:
00549                         FSM_TRANSITION(close_to_target);
00550                         break;
00551                 case EV_TRAJECTORY_DONE_AND_CLOSE:
00552                         FSM_SIGNAL(MAIN, EV_MOTION_DONE);
00553                         FSM_TRANSITION(wait_for_command);
00554                         break;
00555                 case EV_TRAJECTORY_LOST:
00556                         FSM_SIGNAL(MAIN, EV_LOST_DURING_MOTION);
00557                         FSM_TRANSITION(wait_for_command);
00558                         break;
00559                 case EV_MOVE_STOP:
00560                         FSM_TRANSITION(wait_for_command);
00561                         break;
00562                 default:
00563                         // TODO: Macro FSM_DEFAULT prints an ungandled event
00564                         break;
00565         }
00566 }
00567 
00568 
00569 FSM_STATE(close_to_target)
00570 {
00571         switch (FSM_EVENT) {
00572                 case EV_STATE_ENTERED:
00573                         FSM_TIMER(MAX_WAIT_FOR_CLOSE_MS);
00574                         break;
00575                 case EV_TRAJECTORY_DONE_AND_CLOSE:
00576                         FSM_SIGNAL(MAIN, EV_MOTION_DONE);
00577                         FSM_TRANSITION(wait_for_command);
00578                         break;
00579                 case EV_TRAJECTORY_LOST:
00580                 case EV_TIMER:
00581                         stop();
00582                         FSM_SIGNAL(MAIN, EV_LOST_DURING_MOTION);
00583                         FSM_TRANSITION(wait_for_command);
00584                         break;
00585                 case EV_MOVE_STOP:
00586                         FSM_TRANSITION(wait_for_command);
00587                         break;
00588                 case EV_TRAJECTORY_DONE:
00589                 case EV_NEW_TRAJECTORY:
00590                 case EV_LOC_UPDATED:
00591                 case EV_NEW_GOAL:
00592                 case EV_LOC_LOST:
00593                 case EV_INIT:
00594                 case EV_EXIT:
00595                 case EV_RETURN:
00596                 case EV_TIMEOUT:
00597                         DBG_PRINT_EVENT("unhandled event");
00598                         break;
00599         }
00600 }

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