|
Fast Research Interface Library
Manual and Documentation
|
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