OpenEtherCATsociety / SOEM

Simple Open Source EtherCAT Master
Other
1.36k stars 689 forks source link

Issue in achieving Synchronization #294

Closed dabhijeet closed 5 years ago

dabhijeet commented 5 years ago

Hi,

For our project we have made an ethercat_manager class with same functionality as red_test. When we run the program it is not going to the operation enable mode. It is staying in ready to switch on or switched on state. The real time thread used in the program is mentioned below

OSAL_THREAD_FUNC_RT ecatthread()
{
   struct timespec   ts, tleft;
   int ht;
   int64 cycletime;

   clock_gettime(CLOCK_MONOTONIC, &ts);
   ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
   ts.tv_nsec = ht * 1000000;
   cycletime = CYCLE_TIME;
   toff = 0;
   dorun = 0;

     pthread_mutex_lock(&lock);
     ec_send_processdata();
     pthread_mutex_unlock(&lock);
   while(1)
   {  
      /* calculate next cycle start */
      add_timespec(&ts, cycletime + toff);
      /* wait to cycle start */
      clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
      if (dorun>0)
      {  
         pthread_mutex_lock(&lock);
         wkc = ec_receive_processdata(EC_TIMEOUTRET);         
         pthread_mutex_unlock(&lock); 

         dorun++;

         /* if we have some digital output, cycle */
         if( digout ) *digout = (uint8) ((dorun / 16) & 0xff);

         if (ec_slave[0].hasdc)
         {
            /* calulate toff to get linux time and DC synced */
            ec_sync(ec_DCtime, cycletime, &toff);
         }
     pthread_mutex_lock(&lock);
     ec_send_processdata();
     pthread_mutex_unlock(&lock);         
      }
   }
}

Although when we change the above program a little bit like

OSAL_THREAD_FUNC_RT ecatthread()
{
   struct timespec   ts, tleft;
   int ht;
   int64 cycletime;

   clock_gettime(CLOCK_MONOTONIC, &ts);
   ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
   ts.tv_nsec = ht * 1000000;
   //cycletime = *(int*)ptr; /* cycletime in ns */
   cycletime = CYCLE_TIME;
   toff = 0;
   dorun = 0;

   while(1)
   {  
      /* calculate next cycle start */
      add_timespec(&ts, cycletime + toff);
      /* wait to cycle start */
      clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
      if (dorun>0)
      {  
         pthread_mutex_lock(&lock);
         ec_send_processdata();
         wkc = ec_receive_processdata(EC_TIMEOUTRET);  
         pthread_mutex_unlock(&lock); 

         dorun++;

         /* if we have some digital output, cycle */
         if( digout ) *digout = (uint8) ((dorun / 16) & 0xff);

         if (ec_slave[0].hasdc)
         {
            /* calulate toff to get linux time and DC synced */
            ec_sync(ec_DCtime, cycletime, &toff);
         }

      }
   }
}

then it is running fine and the drive is going to the operation enable state. But in this code the Synchronization is getting lost after some days (i.e. 3-6 days).

We didn't get what is the reason for it and why the earlier code was not going to operation enabled mode.

ArthurKetels commented 5 years ago

Post wireshark traces. Perhaps we can find a cause.

dabhijeet commented 5 years ago

Please find the wireshark data.

The code_1.pcapng contains the data of the first code mentioned above. This code is having the flow same as red_test.c but still we are not getting sync with it.

The code_2.pcapng contains the data of the second code mentioned above. This code is little bit different than the red_test.c. The changes are mentioned above. And we are getting sync with it Wireshark data.zip .

nakarlsson commented 5 years ago

What is the purpose of the pthread locks?

dabhijeet commented 5 years ago

Actually we are using EtherCAT Manager as a class. We are connecting it to ROS. So in order to use the shared TPDO and RPDO we are using another function in EtherCAT Manager for read and write. To avoid the usage of shared variables we are using pthread locks.

dabhijeet commented 5 years ago

There is something we observed -

if we change the code like this

OSAL_THREAD_FUNC_RT ecatthread()
{
   struct timespec   ts, tleft;
   int ht;
   int64 cycletime;

   clock_gettime(CLOCK_MONOTONIC, &ts);
   ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
   ts.tv_nsec = ht * 1000000;
   cycletime = CYCLE_TIME;
   toff = 0;
   dorun = 0;

     pthread_mutex_lock(&lock);
     ec_send_processdata();
   while(1)
   {  
      /* calculate next cycle start */
      add_timespec(&ts, cycletime + toff);
      /* wait to cycle start */
      clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
      if (dorun>0)
      {  
         wkc = ec_receive_processdata(EC_TIMEOUTRET);         
         pthread_mutex_unlock(&lock); 
         usleep(3000);
         dorun++;

         /* if we have some digital output, cycle */
         if( digout ) *digout = (uint8) ((dorun / 16) & 0xff);

         if (ec_slave[0].hasdc)
         {
            /* calulate toff to get linux time and DC synced */
            ec_sync(ec_DCtime, cycletime, &toff);
         }
     pthread_mutex_lock(&lock);
     ec_send_processdata();

      }
   }
pthread_mutex_unlock(&lock);  
}

the motor will properly gets synchronized. It seems like if we read or write (ec_slave[slave_no].inputs[channel] and ec_slave[slave_no].outputs[channel] = value) in between ec_send_processdata(); and ec_receive_processdata(EC_TIMEOUTRET); then the synchronization won't happen....

dabhijeet commented 5 years ago

Problem solved.. The above code is working...