[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