[Rtai] Newbie questions

Chris Cole clecol at gmail.com
Wed Mar 16 13:33:30 CET 2011


On 03/15/2011 07:41 PM, Graeme Foot wrote:
>
> Hi,
>
> I'm new to RTAI, Linux (and c).  I do however have a few years 
> experience interacting with motion control cards on windows and 
> creating a few non-realtime motion control emulators using Delphi.  I 
> now want to write my own motion controller using Linux, RTAI and EtherCat.
>
> I've spent the last couple of months getting up to speed with the 
> technologies and have started putting together an RTAI application 
> framework.  I would like to explain my framework and get feedback on 
> whether it is a good approach or not.  My test application is also 
> suffering from a few performance issues which hopefully someone can 
> help with.
>
> My test computer setup is:
>
> Linux Kernel 2.6.29.5
>
> RTAI 3.8.1
>
> EtherCat master 1.5 (from EtherLabs, though not part of this question)
>
> gcc 4.4.3
>
> Intel Celeron M 1GHz
>
> 1GHz ram
>
> My test application:
>
> - User space application using LXRT
>
> - Made up of 3 threads
>
> - The first thread is a Hard Realtime thread running at a 1ms period 
> using oneshot mode
>
> - The second thread is a Soft realtime task that receives buffered 
> data from the first thread (by a sheared memory allocation) and passes 
> this information on to clients that have requested it
>
> - The third thread is a Soft realtime task that acts as a socket 
> server so that clients may connect and send commands
>
> Some pseudo code
>
> Main:
>
> rt_sem_init( "MRTACT" )
>
> rt_sem_init( "CMDSYN" )
>
> rt_thread_create( thread1 )
>
> wait until thread1 polling
>
> rt_thread_create( thread2 )
>
> rt_thread_create( thread3 )
>
> while (!stopApp)
>
> {
>
>   sleep(5);
>
> }
>
> wait for threads to complete
>
> return 0;
>
> Note: the two semaphores ("MRTACT" and "CMDSYN") are used to block 
> access to the datarecord by other threads (if we end up with a dual 
> core CPU) and to wake up any threads waiting for the hard realtime 
> thread to complete its cycle respectively.
>
> Thread 1:
>
> rt_shm_alloc( "KMCMEM", sizeof(datarecord), USE_VMALLOC )
>
> rt_shm_alloc( "DATMEM", sizeof(datarecord)*50, USE_VMALLOC )
>
> rt_task_init_schmod( "KMCMRT",,, SCHED_FIFO )
>
> rt_set_oneshot_mode()
>
> start_rt_timer( 1ms )
>
> rt_allow_nonroot_hrt()
>
> mlockall( MCL_CURRENT | MCL_FUTURE )
>
> rt_make_hard_real_time()
>
> rt_task_make_periodic()
>
> rt_task_wait_period()
>
> while (!stopApp)
>
> {
>
>   scanOverrun = rt_task_wait_period()
>
>   rt_sem_wait( "MRTACT" )
>
>   update nextCycleTime
>
>   update datarecord
>
>   cache datarecord
>
>   {
>
>     memcpy( "DATMEM"[idx], "KMCMEM", sizeof("KMCMEM") )
>
>   }
>
>   rt_sem_signal( "MRTACT" )
>
>   rt_sem_broadcast( "CMDSYN" )
>
> }
>
> rt_make_soft_real_time()
>
> stop_rt_timer()
>
> rt_get_exectime()
>
> rt_task_delete( "KMCMRT" )
>
> rt_shm_free( "DATMEM" )
>
> rt_shm_free( "KMCMEM" )
>
> Thread 2:
>
> rt_task_init( "KMCDAT" )
>
> rt_shm_alloc( "DATMEM" )
>
> while (!stopApp)
>
> {
>
>   rt_sem_wait_timed( "CMDSYN" )
>
>   waitOnRTThread()
>
>   process( "DATMEM" )
>
> }
>
> rt_shm_free( "DATMEM" )
>
> rt_task_delete( "KMCDAT" )
>
> Thread 3: (based on example from: www.tenouk.com/Module41.html)
>
> rt_task_init( "KMCCMD" )
>
> soc = socket( AF_INET,  SOCK_STREAM, 0 )
>
> setsockopt( soc, SOL_SOCKET, SO_REUSEADDR, true )
>
> setsockopt( soc, IPPROTO_TCP, TCP_NODELAY, true )
>
> bind( (AF_INET, htons(SvrPort), htonl(INADDR_ANY)) )
>
> listen()
>
> FD_SET( soc, socSet )
>
> while (!stopApp)
>
> {
>
>   tmpSet = socSet
>
>   select( maxfd+1, tmpSet, NULL, NULL, timeout )
>
>   waitOnRTThread()
>
>   for each fd
>
>   {
>
>     if (FD_ISSET( soc, tmpSet ))
>
>     {
>
>       if (fd == soc)
>
>       {
>
>         // new connection
>
>         FD_SET( newfd, socSet )
>
>       }
>
>       else
>
>       {
>
>         // client request
>
>         if ((nbytes = recv( fd, buf )) <= 0)
>
>         {
>
>           // close connection
>
>           close( fd )
>
>           FD_CLR( fd, socSet )
>
>         }
>
>         else
>
>         {
>
>           processCmd( buf )
>
>           send( fd, reply )
>
>         }
>
>       }
>
>     }
>
>   }
>
> }
>
> rt_task_delete( "KMCCMD" )
>
> The waitOnRTThread() checks to see if thread 1 is busy or about to be busy
>
> void waitOnRTThread()
>
> {
>
>   if (rt_sem_wait_if( "MRTACT" ) < 0)
>
>   {
>
>     if (rt_sem_wait_timed( "MRTACT", 1000000000LL ) >= 0)
>
>     {
>
>       rt_sem_signal( "MRTACT" );
>
>     }
>
>   }
>
>   else
>
>   {
>
>     if (thrd1.nextCycleTime() - rt_get_cpu_time_ns() < 
> CRITICAL_CYCLE_TIME)
>
>     {
>
>       rt_sem_signal( "MRTACT" );
>
>       rt_sem_wait_timed( "CMDSYN", 1000000000LL );
>
>     }
>
>     else
>
>     {
>
>       rt_sem_signal( "MRTACT" );
>
>     }
>
>   }
>
> }
>
> The main concept of what I'm trying to achieve is:
>
> There is one main hard realtime thread (thread 1) that does cyclical 
> processing of the data (ie read ethercat, calc data, write ethercat).
>
> There is one soft realtime thread (thread 3) that acts as a command 
> server that blocks until either a connection request or a client 
> message is received (using select).  My understanding of the 
> SCHED_FIFO scheduler is that when an rt task has focus it will not be 
> preempted by any other rt task, so to ensure the hard realtime thread 
> is not blocked the waitOnRTThread() function is called before 
> processing begins.  It is unlikely that the "MRTACT" semaphore will be 
> in use (as thread 1 will be active) so the primary thing that will 
> happen is that if there is not enough time left we will wait on the 
> "CMDSYN" semaphore which will get woken up the thread 1 once every 
> cycle.  (Note: the other semaphore is checked is case we use a dual 
> core cpu in future.)
>
> The last soft realtime thread (thread 2) is used to pass on the cyclic 
> information from thread 1 to any sockets who have requested the data.  
> I'm using a shared memory cache of 50 records which is being 
> synchronized by a few flags.  At the moment thread 1 is adding a 
> record to the cache every cycle, so this thread should also be woken 
> up every cycle via the rt_sem_wait_timed( "CMDSYN" ).  (I will soon be 
> creating its own event semaphore once I implement variable data 
> gathering rates.)  The idea is to pass on the data to any sockets who 
> have requested datarecord updates, but at the moment I'm just 
> outputting the information every 10 cycles to stdout.
>
> In general the concept seems to be working, but there are a couple of 
> issues:
>
> 1) The hard realtime thread (thread 1) is getting the odd overrun, 
> with the maximum overrun so far around 50us (on a 1ms period).  The 
> latency checking utilities come in with a jitter of approximately 2 to 
> 3us.  I've also hooked up an oscilloscope to an output being toggled 
> every millisecond (via ethercat) with only thread 1 above active 
> without any problems.  /proc/rtai/scheduler has the following parameters:
>
>     Calibrated Time Base Frequency: 999910000 Hz
>
>     Calibrated interrupt to scheduler latency: 2689 ns
>
>     Calibrated oneshot timer setup_to_firing time: 2010 ns
>
> 2) The socket communications are somewhat slower than I hoped for.  
> I'm only managing 4 to 5 requests per cycle (with thread 1 only taking 
> up 3% of its time).  When thread 1 is loaded up to 50% (with a busy 
> wait) then it can only process 1 or 2 requests per cycle.  I have 
> tried a couple the optimizations recommended here 
> (http://www.ibm.com/developerworks/linux/library/l-hisock.html) with 
> little effect.  I am currently only disabling nagle, though I did try 
> the other suggestions without having much effect (but also not really 
> knowing which values to try).
>
> Does anyone have any comments as to whether this is a good approach or 
> maybe have any ideas on how to speed up the socket communications?  (I 
> have not yet investigated UDP.)
>
>

Maybe want to look into RTnet? http://www.rtnet.org/

Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.rtai.org/pipermail/rtai/attachments/20110316/7fb83ef9/attachment-0001.htm>


More information about the Rtai mailing list