2015-04-15 2 views
0

Это часть огромного кода, где я общаюсь с роботом и s7 plc, работая параллельно. Проблема в том, что, прежде чем я, хотя проблема была частью коммуникационного взаимодействия, теперь я сократил весь свой код до клиент-серверного приложения, которое также терпит неудачу. Код в основном работает следующим образом; каждые 50 мс клиент отправляет на сервер сообщение «привет». Когда отправляется 20 сообщений, запускается таймер 7 секунд. Когда таймер запускается, запускается второй поток, и он меняет переменную f = 1, и она завершается. В то же время основная программа будет печатать привет, но когда эта переменная f изменяется на 1, она должна печатать только «aaaaa», но это никогда не произойдет.Проблема связи с tcp при запуске нового потока таймером

С ПЛК возникли проблемы с дефектами сегментации. Моя идея заключается в том, что TCP-связь выходит из строя (почему?), И ПЛК блокирует доступ. Я пробовал одну и ту же программу, прежде чем просто двигать руку робота и анализировать с помощью wirehark, вы можете видеть, как TCP все время отправляется, но опять же, робот останавливается. И, наконец, с помощью этого клиентского приложения можно увидеть, как они не работают так, как ожидалось.

Я надеюсь, что кто-то из вас может мне помочь.

Большое спасибо;)

КЛИЕНТ

#include <stdlib.h> 
 
#include <arpa/inet.h> 
 
#include <stdio.h> 
 
#include <string.h> 
 
#include <sys/types.h> // Primitive System Data Types 
 
#include <errno.h>  // Errors */ 
 
#include <sys/wait.h> // Wait for Process Termination 
 
#include "plc_interface.h" 
 
#include <netinet/in.h> 
 
#include <time.h> 
 
#include <signal.h> 
 
#include <pthread.h> 
 
#include <semaphore.h> 
 
#include <time.h> 
 
#include <unistd.h> 
 
#include <sys/time.h> 
 
#include <fcntl.h> 
 
#include <sys/socket.h> 
 

 
\t timer_t firstTimerID; 
 
\t timer_t secondTimerID; 
 
    struct itimerspec it; 
 
    int t_block3=5; 
 
\t pthread_t thread_robot; 
 
\t pthread_attr_t thread_attr; 
 
\t int res, z; 
 
\t int f=0; 
 
    
 

 

 
//THREAD FUNCTION ONCE THE REQUIRED BLOCK IS DETECTED 
 
void *detection_robot(){ 
 
\t printf("First\n"); 
 
\t //f==1 to send the message aaaaaa 
 
\t f=1; 
 
\t pthread_exit(NULL); 
 

 
} 
 

 

 
int setTimer(timer_t * timerID, int time) { 
 
    struct itimerspec its; 
 
    //Interval for starting again 
 
    its.it_interval.tv_sec = 0; 
 
    its.it_interval.tv_nsec = 0; 
 
    //Timer time 
 
    its.it_value.tv_sec = time; 
 
    its.it_value.tv_nsec = 0; 
 
    //Arm/disarmer a per process time 
 
    timer_settime (*timerID, 0, &its, NULL); 
 

 
    return 0; 
 
} 
 

 
//TIMER INTERRUPTION 
 
static void timerHandler (int sig, siginfo_t * si, void *uc_) { 
 
\t \t timer_t *tidp; 
 
\t \t int iret; 
 
\t \t tidp = si->si_value.sival_ptr; 
 

 
\t \t //Initializes the attributes for the thread 
 
\t \t res= pthread_attr_init(&thread_attr); 
 
\t \t res=pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); 
 

 
\t \t if (*tidp == firstTimerID) { 
 
\t \t \t printf ("First timer\n"); 
 

 
\t \t \t //New thread to detect the second detection sensor 
 
\t \t \t iret = pthread_create(&thread_robot, &thread_attr, detection_robot, NULL); 
 
\t \t \t if(iret) 
 
\t \t \t \t { 
 
\t \t \t \t fprintf(stderr,"Error - pthread_create() return code: %d\n",iret); 
 
\t \t \t \t exit(EXIT_FAILURE); 
 
\t \t \t \t } 
 
\t \t } else if (*tidp == secondTimerID) { 
 
\t \t \t printf ("Second timer\n"); 
 
\t \t } 
 

 
\t \t z--; 
 

 
} 
 

 

 
//ARM THE TIMERS 
 
static int makeTimer (timer_t * timerID) { 
 
\t \t struct sigevent te; 
 
\t \t struct sigaction sa; 
 
\t \t int sigNo = SIGRTMIN; 
 
\t \t // Set up signal handler. 
 
\t \t sa.sa_flags = SA_SIGINFO; 
 
\t \t sa.sa_sigaction = timerHandler;  //Action when singal is triggered 
 
\t \t sigemptyset (&sa.sa_mask); 
 
\t \t if (sigaction (sigNo, &sa, NULL) == -1) { 
 
\t \t \t perror ("sigaction"); 
 
\t \t \t \t } 
 
\t \t // Set and enable alarm 
 
\t \t te.sigev_notify = SIGEV_SIGNAL;  //Gnerate alarm upon expiration 
 
\t \t te.sigev_signo = sigNo;  //SIGALRM 
 
\t \t te.sigev_value.sival_ptr = timerID; //Timer ID 
 
\t \t //Create a per_process timer using the timer ID 
 
\t \t timer_create (CLOCK_REALTIME, &te, timerID); 
 
\t \t return 0; 
 
} 
 

 

 
int main(int argc , char *argv[]) 
 
{ 
 
    int sock; 
 
    struct sockaddr_in server; 
 
    char message[6]={'h','e','l','l','o','\0'}; 
 
     char message2[6]={'a','a','a','a','a','\0'}; 
 
    char server_reply[2000]; 
 
\t //Initialize the timers 
 
\t makeTimer(&firstTimerID); 
 
\t makeTimer(&secondTimerID); 
 

 
    //Create socket 
 
    sock = socket(AF_INET , SOCK_STREAM , 0); 
 
    if (sock == -1) 
 
    { 
 
     printf("Could not create socket"); 
 
    } 
 
    puts("Socket created"); 
 
     
 
    server.sin_addr.s_addr = inet_addr("127.0.0.1"); 
 
    server.sin_family = AF_INET; 
 
    server.sin_port = htons(8888); 
 
    
 
    //Connect to remote server 
 
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) 
 
    { 
 
     perror("connect failed. Error"); 
 
     return 1; 
 
    } 
 
    puts("Connected\n"); 
 
    //keep communicating with server 
 
\t int i=0; 
 
\t while(1){ 
 
     //Send hello every 50ms 
 
     if(send(sock , message , 6 , 0) < 0) 
 
     { 
 
      puts("Send failed"); 
 
      return 1; 
 
     } 
 
\t \t \t i++; 
 
\t \t \t if (i==20){ 
 
\t \t \t \t \t \t setTimer (&firstTimerID, t_block3); 
 
\t \t \t \t \t \t i=0; 
 
\t \t \t \t \t } 
 
\t \t \t \t \t 
 
\t \t \t //f-> 1, send aaaaaa when timer is triggered, but here is when it get stacked 
 
\t \t \t if (f==1) { 
 
\t \t \t \t f=0; 
 
\t \t \t \t if(send(sock , message2 , 6 , 0) < 0) 
 
\t \t \t \t { 
 
\t \t \t \t \t puts("Send failed"); 
 
\t \t \t \t \t return 1; 
 
\t \t \t \t }} 
 

 
\t \t \t usleep(500000); //500ms 
 
\t \t } 
 

 
}

SERVER


 
#include<stdio.h> 
 
#include<string.h> //strlen 
 
#include<sys/socket.h> 
 
#include<arpa/inet.h> //inet_addr 
 
#include<unistd.h> //write 
 
    
 
int main(int argc , char *argv[]) 
 
{ 
 
    int socket_desc , client_sock , c , read_size; 
 
    struct sockaddr_in server , client; 
 
    char client_message[2000]; 
 
     
 
    //Create socket 
 
    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
 
    if (socket_desc == -1) 
 
    { 
 
     printf("Could not create socket"); 
 
    } 
 
    puts("Socket created"); 
 
     
 
    //Prepare the sockaddr_in structure 
 
    server.sin_family = AF_INET; 
 
    server.sin_addr.s_addr = INADDR_ANY; 
 
    server.sin_port = htons(8888); 
 
     
 
    //Bind 
 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) 
 
    { 
 
     //print the error message 
 
     perror("bind failed. Error"); 
 
     return 1; 
 
    } 
 
    puts("bind done"); 
 
     
 
    //Listen 
 
    listen(socket_desc , 3); 
 
     
 
    //Accept and incoming connection 
 
    puts("Waiting for incoming connections..."); 
 
    c = sizeof(struct sockaddr_in); 
 
     
 
    //accept connection from an incoming client 
 
    client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); 
 
    if (client_sock < 0) 
 
    { 
 
     perror("accept failed"); 
 
     return 1; 
 
    } 
 
    puts("Connection accepted"); 
 
     
 
    while(1){ 
 
    //Receive a message from client 
 
    recv(client_sock , client_message , 2000 , 0); 
 
    printf("%s\n", client_message); 
 
     
 
\t } 
 

 
}

+0

что выход? можете ли вы запустить его с помощью отладчика и сказать, где он разбился? –

ответ

0

Проблема заключается в том, что назначение:

f = 1; 

не видно других тем, поэтому нить main() не видит изменений. Чтобы исправить это, вам нужно будет использовать механизм синхронизации, такой как pthread_mutex_t, который должен быть получен при чтении или записи f или atomic_int, если ваш компилятор поддерживает C11.

+0

Я пробовал использовать семафоры, но он тоже не работал. Я продолжу мьютексы. Спасибо – landondonovan

0

РЕШИТЬ, объяснение в комментариях :)

Кода был решен просто добавив семафоры, как предложил hmjd. Спасибо;)

У меня не было ясно, что это вопрос мьютекса, поскольку в других кодах, с которыми я работаю, нет общих переменных, которые могут вызвать разрывы кода/связи. Я представлю здесь свой код, чтобы показать, с чем я работаю. Я удалил дополнительную связь tcp с роботом, я просто представляю здесь непрерывное чтение памяти ПЛК, которое работает довольно стабильно все время, но ломается (не всегда), когда запускается простой таймер. Если сменить ПЛК для робота, который является просто нормальным сообщением о передаче сообщений tcp, все равно происходит то же самое.

#include <stdlib.h> 
 
#include <arpa/inet.h> 
 
#include <stdio.h> 
 
#include <string.h> 
 
#include "nodavesimple.h" 
 
#include "nodave.h" 
 
#include "openSocket.h" 
 
#include "plc_interface.h" 
 
#include <sys/types.h> // Primitive System Data Types 
 
#include <errno.h>  // Errors */ 
 
#include <sys/wait.h> // Wait for Process Termination 
 
#include "plc_interface.h" 
 
#include <netinet/in.h> 
 
#include <time.h> 
 
#include <signal.h> 
 
#include <pthread.h> 
 
#include <semaphore.h> 
 
#ifdef LINUX 
 
#include <unistd.h> 
 
#include <sys/time.h> 
 
#include <fcntl.h> 
 
#define UNIX_STYLE 
 
#endif 
 

 
#ifdef BCCWIN 
 
#include <time.h> 
 
    void usage(void); 
 
#define WIN_STYLE 
 

 
#endif 
 

 

 
#ifdef PLAY_WITH_KEEPALIVE 
 
#include <sys/socket.h> 
 
#endif 
 

 

 

 
\t timer_t firstTimerID; 
 
    struct itimerspec it; 
 
    int t_block3=3; 
 
\t pthread_t thread_robot; 
 
\t pthread_attr_t thread_attr; 
 
\t int robot_detection=0; 
 

 

 

 

 
//THREAD FUNCTION ONCE THE REQUIRED BLOCK IS DETECTED 
 
void *detection_robot(){ 
 
\t printf("First\n"); 
 
\t pthread_exit(0); 
 

 
} 
 

 

 

 

 
//TIMER INTERRUPTION 
 
static void timerHandler (int sig, siginfo_t * si, void *uc_) { 
 
\t \t timer_t *tidp; 
 
\t \t int iret; 
 
\t \t tidp = si->si_value.sival_ptr; 
 

 
\t \t //Initializes the attributes for the thread 
 
\t \t pthread_attr_init(&thread_attr); 
 
\t \t pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); 
 

 
\t \t if (*tidp == firstTimerID) { 
 
\t \t \t printf ("First timer\n"); 
 

 
\t \t \t //New thread to detect the second detection sensor 
 
\t \t \t iret = pthread_create(&thread_robot, &thread_attr, detection_robot, NULL); 
 
\t \t \t if(iret) 
 
\t \t \t \t { 
 
\t \t \t \t fprintf(stderr,"Error - pthread_create() return code: %d\n",iret); 
 
\t \t \t \t exit(EXIT_FAILURE); 
 
\t \t \t \t } 
 
\t \t } 
 

 

 
} 
 

 

 
//ARM THE TIMERS 
 
static int makeTimer (timer_t * timerID) { 
 
\t \t struct sigevent te; 
 
\t \t struct sigaction sa; 
 
\t \t int sigNo = SIGRTMIN; 
 
\t \t // Set up signal handler. 
 
\t \t sa.sa_flags = SA_SIGINFO; 
 
\t \t sa.sa_sigaction = timerHandler;  //Action when singal is triggered 
 
\t \t sigemptyset (&sa.sa_mask); 
 
\t \t if (sigaction (sigNo, &sa, NULL) == -1) { 
 
\t \t \t perror ("sigaction"); 
 
\t \t \t \t } 
 
\t \t // Set and enable alarm 
 
\t \t te.sigev_notify = SIGEV_SIGNAL;  //Gnerate alarm upon expiration 
 
\t \t te.sigev_signo = sigNo;  //SIGALRM 
 
\t \t te.sigev_value.sival_ptr = timerID; //Timer ID 
 
\t \t //Create a per_process timer using the timer ID 
 
\t \t timer_create (CLOCK_REALTIME, &te, timerID); 
 
\t \t return 0; 
 
} 
 

 

 

 

 

 
int main(int argc, char **argv) { 
 
    int adrPos, useProtocol, useSlot; 
 
    int res,barcode_number, r, t; 
 
    int c=0, a=0; 
 
    //Locate the robot in the initial position 
 
    //robot_init(); 
 

 
\t //Initialize the timer 
 
\t makeTimer(&firstTimerID); 
 

 

 
#ifdef PLAY_WITH_KEEPALIVE 
 
    int opt; 
 
#endif 
 

 
    daveSetDebug(daveDebugPrintErrors); 
 
    adrPos=1; 
 
    useProtocol=daveProtoISOTCP; 
 
    useSlot=2; 
 
    daveInterface * di; 
 
    daveConnection * dc; 
 
    _daveOSserialType fds; 
 
    PDU p; 
 
    daveResultSet rs; 
 

 
    //If the input doesn't have enough parameters, printf the usage 
 
    if (argc<2) { 
 
\t \t usage(); 
 
\t \t exit(-1); 
 
    } 
 

 

 

 
\t //If there is a problem in the communication it takes 20 seconds to stablish communication again 
 
    fds.rfd=openSocket(102, argv[adrPos]); 
 

 
#ifdef PLAY_WITH_KEEPALIVE 
 
    errno=0; 
 
    opt=1; 
 
    res=setsockopt(fds.rfd, SOL_SOCKET, SO_KEEPALIVE, &opt, 4); 
 
    LOG3("setsockopt %s %d\n", strerror(errno),res); 
 
#endif 
 
    fds.wfd=fds.rfd; 
 

 
    if (fds.rfd>0) { 
 
\t di =daveNewInterface(fds,"IF1",0, useProtocol, daveSpeed187k); 
 
\t daveSetTimeout(di,5000000); 
 
\t dc =daveNewConnection(di,2,0,useSlot); // insert your rack and slot here 
 
\t if (0==daveConnectPLC(dc)) { 
 
\t  printf("Connected.\n"); 
 

 
\t \t \t //START THE BELT 
 
\t   a=0;//a=1 to start the belt 
 
\t   printf("Start the belt \n"); 
 
\t   res=daveWriteBits(dc, daveDB, 111, 4, 1, &a); 
 
\t   res=daveWriteBits(dc, daveDB, 111, 3, 1, &a); 
 
\t   printf("function result:%d=%s\n", res, daveStrerror(res)); 
 

 
\t \t \t \t //Remove the memory flag of the detection sensor again 
 
\t \t \t \t res=daveWriteBits(dc, daveFlags, 0, 504, 1, &c); 
 
\t \t \t \t res=daveWriteBits(dc, daveFlags, 0, 520, 1, &c); 
 

 
\t \t \t \t usleep(2000000); 
 
\t \t \t \t printf("Trying to read the sensor until block is detected\n"); 
 
\t \t \t \t //SENSOR DETECTION 
 
\t \t \t \t while(1){ 
 

 
\t \t \t \t \t //Read request --> Stable until the timer is triggered 
 
\t \t \t \t \t davePrepareReadRequest(dc,&p); 
 
\t \t \t \t \t daveAddVarToReadRequest(&p, daveFlags, 0, 63, 1); 
 
\t \t \t \t \t daveAddVarToReadRequest(&p, daveFlags, 0, 65, 1); 
 
\t \t \t \t \t daveAddVarToReadRequest(&p, daveDB, 4, 103, 1); 
 
\t \t \t \t \t res=daveExecReadRequest(dc, &p, &rs); 
 
\t \t \t \t \t if (res==1){ \t printf("Error during the request\n");} 
 

 
\t \t \t \t \t //First result --> detection sensor after the barcode 
 
\t \t \t \t \t res=daveUseResult(dc, &rs, 0); 
 
\t \t \t \t \t if (res==1){ \t printf("Error reading the first result\n");} 
 
\t \t \t \t  t=daveGetU8(dc); //T = 1 if detection in the barcode place 
 
\t \t \t \t  //Second result --> detection sensor before the robot position 
 
\t \t \t \t \t res=daveUseResult(dc, &rs, 1); 
 
\t \t \t \t \t if (res==1){ \t printf("Error reading the detection sensor before the robot\n");} 
 
\t \t \t \t \t r=daveGetU8(dc); //R = 1 if detection in the robot place 
 
\t \t \t \t \t //Third result --> read the number stored 
 
\t \t \t \t \t daveUseResult(dc, &rs, 2); 
 
\t \t \t \t \t barcode_number=daveGetU8(dc); 
 
\t \t \t \t \t //Free the memory 
 
\t \t \t \t \t daveFreeResults(&rs); 
 

 
\t \t \t \t \t if (r==1){ 
 
\t \t \t \t \t \t //Remove the memory flag referred to the second sensor 
 
\t \t \t \t \t \t res=daveWriteBits(dc, daveFlags, 0, 520, 1, &c); 
 
\t \t \t \t \t \t if (res==1){ \t printf("Error removing the flag of the second detector\n");} 
 
\t \t \t \t \t } 
 

 
\t \t \t \t \t //Wen detection.. 
 
\t \t \t \t \t if (t==1){ 
 
\t \t \t \t \t \t \t t=0; 
 
\t \t \t \t \t \t \t //Remove the memory flag of the detection 
 
\t \t \t \t \t \t \t res=daveWriteBits(dc, daveFlags, 0, 504, 1, &c); 
 
\t \t \t \t \t \t \t if (res==1){ \t printf("Error removing the flag of the sensor closed to the robot\n");} 
 

 

 
\t \t \t \t \t \t \t //If number three is detected the belt will stop in 3 seconds respectively 
 
\t \t \t \t \t \t \t switch(barcode_number){ 
 

 
\t \t \t \t \t \t \t case 3: printf("Block number three, timer will be triggered in 3 seconds\n"); 
 
\t \t \t \t \t \t \t \t \t //Start the timer 
 
\t \t \t \t \t \t \t \t \t setTimer (&firstTimerID, t_block3); 
 
\t \t \t \t \t \t \t \t \t break; 
 

 
\t \t \t \t \t \t \t case 2: printf("Block number two, belt won't stop\n"); 
 
\t \t \t \t \t \t \t \t \t break; 
 

 
\t \t \t \t \t \t \t case 4: printf("Block number four, belt won't stop\n"); 
 
\t \t \t \t \t \t \t \t \t break; 
 

 
\t \t \t \t \t \t \t default:printf("Wrong lecture\n"); 
 

 
\t \t \t \t \t \t \t }} 
 

 

 
\t \t \t \t \t usleep(50000); //Rest until next sampling 
 
\t \t } 
 
\t //Close socket 
 
\t closeSocket(fds.rfd); 
 
\t printf("Finished.\n"); 
 

 
\t return 0; 
 
\t } else {//daveconnected 
 
\t  printf("Couldn't connect to PLC.\n \n"); 
 
\t  closeSocket(fds.rfd); 
 
\t  return -2;} 
 

 
    }//fds.rds > 0 
 
    else { 
 
\t printf("Couldn't open TCP port. \nPlease make sure a CP is connected and the IP address is ok. \n"); 
 
    \t return -1; 
 
    } 
 
}

+0

Наконец-то я решил все проблемы. Я попытаюсь их прояснить. Для робота. Вы отправляете несколько команд tcp, и вам нужно некоторое время спать, ожидая, пока робот не достигнет положения, которое вы просили.Затем отправьте новую команду tcp для новой позиции. С таймерами, когда он запускается, может быть, что робот находится в ожидании до достижения позиции, поэтому, если время срабатывает, когда таймер-манипулятор заканчивается, код выполняет следующую строку, не оставляя роботу достаточно времени, чтобы добраться до позиции. .. и это ломается. Этот робот - UR10. – landondonovan

+0

Для кода, который я только что представил выше, точно такой же. Инструкции, запрашивающие доступ к памяти, могут случиться, что таймер запускается и перескакивает с одной из этих важных инструкций. И затем в следующих инструкциях он пытается прочитать одну из ранее не запрошенных воспоминаний, что делает ошибку сегментации. – landondonovan

Смежные вопросы