Fast Research Interface Library  Manual and Documentation
src/FastResearchInterfaceLibrary/FastResearchInterface.cpp
Go to the documentation of this file.
00001 //  ---------------------- Doxygen info ----------------------
00050 //  ----------------------------------------------------------
00051 //   For a convenient reading of this file's source code,
00052 //   please use a tab width of four characters.
00053 //  ----------------------------------------------------------
00054 
00055 
00056 #include <FastResearchInterface.h>
00057 #include <Console.h>
00058 #include <pthread.h>
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <string.h>
00062 #include <signal.h>
00063 #include <errno.h>
00064 #include <stdarg.h>
00065 #include <OSAbstraction.h>
00066 
00067 
00068 
00069 #define MAX_ROBOT_NAME_LENGTH               256
00070 #define MAX_OUTPUT_PATH_LENGTH              256
00071 #define MAX_FILE_NAME_LENGTH                256
00072 #define SIZE_OF_ROBOT_STATE_STRING          4096
00073 
00074 
00075 // ****************************************************************
00076 // Constructor
00077 //
00078 FastResearchInterface::FastResearchInterface(const char *InitFileName)
00079 {
00080     int                 ParameterCount                      =   0
00081                     ,   FuntionResult                       =   0;
00082 
00083     struct sched_param      SchedulingParamsKRCCommunicationThread
00084                         ,   SchedulingParamsTimerThread
00085                         ,   SchedulingParamsMainThread;
00086 
00087     pthread_attr_t          AttributesKRCCommunicationThread
00088                         ,   AttributesTimerThread;
00089 
00090     this->RobotName             =   new char[MAX_ROBOT_NAME_LENGTH];
00091     this->LoggingPath           =   new char[MAX_OUTPUT_PATH_LENGTH];
00092     this->LoggingFileName       =   new char[MAX_FILE_NAME_LENGTH];
00093     this->RobotStateString      =   new char[SIZE_OF_ROBOT_STATE_STRING];
00094 
00095     memset((void*)(this->RobotName)             , 0x0   , MAX_ROBOT_NAME_LENGTH         * sizeof(char));
00096     memset((void*)(this->LoggingPath)           , 0x0   , MAX_OUTPUT_PATH_LENGTH        * sizeof(char));
00097     memset((void*)(this->LoggingFileName)       , 0x0   , MAX_FILE_NAME_LENGTH          * sizeof(char));
00098     memset((void*)(this->RobotStateString)      , 0x0   , SIZE_OF_ROBOT_STATE_STRING    * sizeof(char));
00099 
00100     ParameterCount  =   this->ReadInitFile(InitFileName);
00101 
00102     if (ParameterCount == -1)
00103     {
00104         fprintf(stderr, "FastResearchInterface::FastResearchInterface(): ERROR, an initialization file name is required! QUITTING.\n");
00105         getchar();
00106         exit(EXIT_FAILURE); // terminates the process
00107     }
00108 
00109     if (ParameterCount < 9)
00110     {
00111         fprintf(stderr, "FastResearchInterface::FastResearchInterface(): ERROR, initialization file \'%s\' is incomplete. Only %d parameters are given. QUITTING.\n", InitFileName, ParameterCount);
00112         getchar();
00113         exit(EXIT_FAILURE); // terminates the process
00114     }
00115 
00116     this->OutputConsole                     =   new Console(PriorityOutputConsoleThread);
00117 
00118     this->TerminateTimerThread              =   false;
00119     this->TerminateKRCCommunicationThread   =   false;
00120     this->TimerFlag                         =   false;
00121     this->NewDataFromKRCReceived            =   false;
00122     this->LoggingIsActive                   =   false;
00123     this->ThreadCreated                     =   false;  
00124 
00125     this->LoggingState                      =   FastResearchInterface::WriteLoggingDataFileCalled;
00126 
00127     this->CurrentControlScheme              =   FastResearchInterface::JOINT_POSITION_CONTROL;
00128 
00129     memset((void*)(&(this->CommandData))    , 0x0   ,                                       sizeof(tFriCmdData) );
00130     memset((void*)(&(this->ReadData))       , 0x0   ,                                       sizeof(tFriMsrData) );
00131 
00132     pthread_mutex_init(&(this->MutexForControlData              ), NULL);
00133     pthread_mutex_init(&(this->MutexForCondVarForTimer          ), NULL);
00134     pthread_mutex_init(&(this->MutexForLogging                  ), NULL);
00135     pthread_mutex_init(&(this->MutexForThreadCreation           ), NULL);
00136 
00137     pthread_cond_init(&(this->CondVarForTimer                   ), NULL);
00138     pthread_cond_init(&(this->CondVarForDataReceptionFromKRC    ), NULL);
00139     pthread_cond_init(&(this->CondVarForThreadCreation          ), NULL);
00140 
00141     this->OutputConsole->printf("Fast Research Interface: Using initialization file \"%s\".\n", InitFileName);
00142 
00143     // Thread configuration
00144 
00145     // get default information
00146 
00147     // set thread attributes to default values:
00148     //      detachstate         PTHREAD_CREATE_JOINABLE
00149     //      schedpolicy         PTHREAD_INHERIT_SCHED
00150     //      schedparam          Inherited from parent thread
00151     //      contentionscope     PTHREAD_SCOPE_SYSTEM
00152     //      stacksize           4K bytes
00153     //      stackaddr           NULL
00154 
00155     // Set the priorities from the initialization file.
00156     SchedulingParamsKRCCommunicationThread.sched_priority   =   PriorityKRCCommunicationThread                      ;
00157     SchedulingParamsTimerThread.sched_priority              =   PriorityTimerThread                                 ;
00158     SchedulingParamsMainThread.sched_priority               =   PriorityMainThread                                  ;
00159 
00160     pthread_attr_init(&AttributesKRCCommunicationThread                                                         )   ;
00161     pthread_attr_init(&AttributesTimerThread                                                                    )   ;
00162 
00163     // Set the thread scheduling policy attribute to round robin
00164     // default is OTHER which equals RR in QNX 6.5.0.
00165     pthread_attr_setschedpolicy(&AttributesKRCCommunicationThread   ,   SCHED_FIFO                              )   ;
00166     pthread_attr_setschedpolicy(&AttributesTimerThread              ,   SCHED_FIFO                              )   ;
00167 
00168     // Set the thread's inherit-scheduling attribute to explicit
00169     // otherwise, the scheduling parameters Cannot be changed (e.g., priority)
00170     pthread_attr_setinheritsched(&AttributesKRCCommunicationThread  ,   PTHREAD_EXPLICIT_SCHED                  )   ;
00171     pthread_attr_setinheritsched(&AttributesTimerThread             ,   PTHREAD_EXPLICIT_SCHED                  )   ;
00172 
00173     pthread_attr_setschedparam(&AttributesKRCCommunicationThread    ,   &SchedulingParamsKRCCommunicationThread )   ;
00174     pthread_attr_setschedparam(&AttributesTimerThread               ,   &SchedulingParamsTimerThread            )   ;
00175 
00176     // this is supposed to become the message thread
00177     // i.e. we have to set our own scheduling parameters
00178     this->MainThread = pthread_self();
00179     pthread_setschedparam(this->MainThread, SCHED_FIFO, &SchedulingParamsMainThread);
00180     
00181 #ifdef WIN32
00182 
00183     if(!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
00184     {
00185         this->OutputConsole->printf("FastResearchInterface::FastResearchInterface(): ERROR, could not set process priority.\n");
00186     } 
00187 
00188 #endif
00189 
00190 
00191     FuntionResult   =   pthread_create(     &TimerThread
00192                                         ,   &AttributesTimerThread
00193                                         ,   &TimerThreadMain
00194                                         ,   this);
00195 
00196     if (FuntionResult != EOK)
00197     {
00198         this->OutputConsole->printf("FastResearchInterface::FastResearchInterface(): ERROR, could not start the timer thread (Result: %d).\n", FuntionResult);
00199         getchar();
00200         exit(EXIT_FAILURE); // terminates the process
00201     }
00202     
00203     pthread_mutex_lock(&(this->MutexForThreadCreation));    
00204     
00205     while (!ThreadCreated)
00206     {
00207         pthread_cond_wait (&(this->CondVarForThreadCreation), &(this->MutexForThreadCreation));
00208     }
00209 
00210     ThreadCreated   =   false;
00211     pthread_mutex_unlock(&(this->MutexForThreadCreation));  
00212 
00213     FuntionResult   =   pthread_create(     &KRCCommunicationThread
00214                                         ,   &AttributesKRCCommunicationThread
00215                                         ,   &KRCCommunicationThreadMain
00216                                         ,   this);
00217                                         
00218     if (FuntionResult != EOK)
00219     {
00220         this->OutputConsole->printf("FastResearchInterface::FastResearchInterface(): ERROR, could not start the KRC communication thread (Result: %d).\n", FuntionResult);
00221         getchar();
00222         exit(EXIT_FAILURE); // terminates the process
00223     }
00224     
00225     pthread_mutex_lock(&(this->MutexForThreadCreation));
00226 
00227     while (!ThreadCreated)
00228     {
00229         pthread_cond_wait (&(this->CondVarForThreadCreation), &(this->MutexForThreadCreation));
00230     }
00231 
00232     ThreadCreated   =   false;
00233     pthread_mutex_unlock(&(this->MutexForThreadCreation));
00234 
00235     if (strlen(this->LoggingPath) > 0)
00236     {
00237         if (strcmp(&(this->LoggingPath[strlen(this->LoggingPath) - 1]), OS_FOLDER_SEPARATOR) != 0)
00238         {
00239             strcat(this->LoggingPath, OS_FOLDER_SEPARATOR);
00240         }
00241     }
00242     else
00243     {
00244         sprintf(this->LoggingPath, ".%s", OS_FOLDER_SEPARATOR);
00245     }
00246 
00247     if (strlen(this->LoggingFileName) == 0)
00248     {
00249         sprintf(this->LoggingFileName, "FRI.dat");
00250     }
00251 
00252     this->DataLogger    =   new DataLogging(    this->RobotName
00253                                             ,   this->LoggingPath
00254                                             ,   this->LoggingFileName
00255                                             ,   this->NumberOfLoggingFileEntries);
00256 }
00257 
00258 
00259 // ****************************************************************
00260 // Destructor
00261 //
00262 FastResearchInterface::~FastResearchInterface(void)
00263 {
00264     int     ResultValue     =   0;
00265 
00266     // End the timer thread
00267     pthread_mutex_lock(&(this->MutexForCondVarForTimer));
00268     this->TerminateTimerThread = true;
00269     pthread_mutex_unlock(&(this->MutexForCondVarForTimer));
00270     pthread_join(this->TimerThread, NULL);
00271 
00272     // Bad workaround for the KUKA friUDP class, which unfortunately
00273     // does not use select() for sockets in order to enable timeouts.
00274     //
00275     // For the case, no UDP connection to the KRC could be
00276     // established, we have to wake up the communication thread
00277     // by sending a signal as it is still waiting for a message
00278     // from the KRC.
00279     
00280     pthread_mutex_lock(&(this->MutexForControlData));
00281     this->NewDataFromKRCReceived = false;
00282     pthread_mutex_unlock(&(this->MutexForControlData));
00283 
00284     delay(1 + 2 * (unsigned int)(this->CycleTime));
00285 
00286     pthread_mutex_lock(&(this->MutexForControlData));
00287     if (this->NewDataFromKRCReceived)
00288     {
00289         pthread_mutex_unlock(&(this->MutexForControlData));
00290 
00291         if (this->IsMachineOK())
00292         {
00293             this->StopRobot();
00294         }
00295 
00296         // The KRL program running on the robot controller waits for a
00297         // integer value change at position 15 (i.e., 16 in KRL).
00298         // A value of 30 or 40 (depending on the value of
00299         // this->GetKRLIntValue(14), that is, $FRI_TO_INT[15]
00300         // lets the KRL program call friClose() and
00301         // terminate itself.
00302 
00303         this->SetKRLIntValue(15, this->GetKRLIntValue(14));
00304 
00305         // wait for the next data telegram of the KRC unit
00306         pthread_mutex_lock(&(this->MutexForControlData));
00307         this->NewDataFromKRCReceived    =   false;
00308         pthread_mutex_unlock(&(this->MutexForControlData));
00309         ResultValue =   this->WaitForKRCTick(((unsigned int)(this->CycleTime * 3000000.0)));
00310 
00311         if (ResultValue != EOK)
00312         {
00313             this->OutputConsole->printf("FastResearchInterface::~FastResearchInterface(): ERROR, the KRC unit does not respond anymore. Probably the FRI was closed or there is no UDP connection anymore.");
00314             getchar();
00315             pthread_kill(this->KRCCommunicationThread, SIGTERM);
00316         }
00317 
00318         // wait until the KRL program ended
00319         // (no UDP communication possible anymore)
00320         delay(800);
00321 
00322         // End the KRC communication thread
00323         pthread_mutex_unlock(&(this->MutexForControlData));
00324         // The UDP communication is working --> normal shutdown
00325         this->TerminateKRCCommunicationThread = true;
00326         pthread_mutex_unlock(&(this->MutexForControlData));
00327     }
00328     else
00329     {
00330         // No UDP communication to KRC and the communication
00331         // thread is blocked --> we wake him up manually
00332         this->TerminateKRCCommunicationThread = true;
00333         pthread_mutex_unlock(&(this->MutexForControlData));
00334         pthread_kill(this->KRCCommunicationThread, SIGTERM);
00335     }
00336     
00337 #ifndef WIN32
00338     pthread_join(this->KRCCommunicationThread, NULL);
00339 #endif
00340 
00341     if (this->LoggingState != FastResearchInterface::WriteLoggingDataFileCalled)
00342     {
00343         this->WriteLoggingDataFile();
00344     }
00345 
00346     delete[]    this->RobotName         ;
00347     delete[]    this->LoggingPath       ;
00348     delete[]    this->LoggingFileName   ;
00349     delete[]    this->RobotStateString  ;
00350     delete      this->DataLogger        ;
00351     delete      this->OutputConsole     ;
00352 }
00353 
00354 
00355 // ****************************************************************
00356 // printf()
00357 //
00358 int FastResearchInterface::printf(const char* Format,...)
00359 {
00360     int         Result      =   0;
00361 
00362     va_list     ListOfArguments;
00363 
00364     va_start(ListOfArguments, Format);
00365 
00366     Result = this->OutputConsole->printf(Format, ListOfArguments);
00367 
00368     va_end(ListOfArguments);
00369 
00370     return(Result);
00371 }
00372 
This document was generated with Doxygen on Thu Apr 12 2012 11:18:54. User documentation of the Fast Research Interface Library for the KUKA Lightweight Robot IV by the Stanford Robotics Research Group. Copyright 2010–2012.