Tag Archives: robot

RT Periodic Thread Code and Scheduler Policy and Priority

in this post, I am going to share an example code creating two threads running with a periodic cycle in an RT Preempt Linux.

You can download the code in this link.

https://github.com/queristq/rt_periodic_thread/archive/master.zip or you can git clone by git clone https://github.com/queristq/rt_periodic_thread.git

To build the code,

  • mkdir build
  • cd build
  • cmake ..
  • make

RT Performance between SCHED_RT and SCHED_IDLE

In the code, I have created two threads, and tested the RT performance for two different thread schedule policy between SCHED_RT and SCHED_IDLE. The figure below shows the result. The blue line shows the log10-scaled histogram of the loop time, and the orange line shows the log10-scaled histogram of the loop time. As shown in the plot, SCHED_RT made low jitters in the periodic loops. The test environment was not strictly controlled (I did internet browsing… while the loop was running).

1

RT Performance over Different Thread Priorities

I have conducted similar tests with different thread priority. I have selected the same thread policy SCHED_FIFO, and the priority of two threads were chosen to 1 and 99 respectively. The jitters of the each loop is shown in the figure below. As shown in the figure, interestingly the difference was very minor. Once you see the details, you can see the result of Priority 1 is slightly better.

2

If you want a full result, you can see the test result in the attached excel sheet.

Example code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

#define TIMESPEC_ADD(A,B) /* A += B */ \
    do {                                   \
    (A).tv_sec += (B).tv_sec;          \
    (A).tv_nsec += (B).tv_nsec;        \
    if ( (A).tv_nsec >= 1000000000 ) { \
    (A).tv_sec++;                  \
    (A).tv_nsec -= 1000000000;     \
    }                                  \
    } while (0)

#define TIMESPEC_SUB(A,B) /* A -= B */ \
    do {                                   \
    (A).tv_sec -= (B).tv_sec;          \
    (A).tv_nsec -= (B).tv_nsec;        \
    if ( (A).tv_nsec < 0 ) {           \
    (A).tv_sec--;                  \
    (A).tv_nsec += 1000000000;     \
    }                                  \
    } while (0)


void *thread_func ( void *param )
{
    FILE *fp;
    char filename_fp[50];

    long thread_id = (long) param;

    sprintf (filename_fp, "%ld%s", thread_id, ".txt");
    fp = fopen(filename_fp, "w");//opening file

    struct timespec t_next, period, t_now, t_prev, t_diff;

    /* period = 1 ms * thread_id */
    period.tv_sec = 0;
    period.tv_nsec = ( 1 ) * 500000; // a x ms

    clock_gettime ( CLOCK_MONOTONIC, &t_now );
    t_next = t_now;
    t_prev = t_now;

    int t_jitter[100];
    for (int i=0;i<100;i++) t_jitter[i] = 0;
    int t_j = 0;

    for ( int i = 0; i < 100000; i++ )
    {
        clock_gettime ( CLOCK_MONOTONIC, &t_now );
        t_diff = t_now;
        TIMESPEC_SUB ( t_diff, t_prev );
        t_prev = t_now;
        t_j = t_diff.tv_nsec / 10000;
        if (t_j<0) t_jitter[0]++;
        else if (t_j>99) t_jitter[99]++;
        else t_jitter[t_j]++;
        if(i%10000==1) printf("%d\n",i);
        TIMESPEC_ADD ( t_next, period );
        clock_nanosleep ( CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL );
    }

    for (int i=0;i<100;i++) {
        printf("%d ",t_jitter[i]);
        fprintf(fp, "%d\n",t_jitter[i]);
    }
    fclose(fp);
    return NULL;
}

int main ()
{
    int policy;
    struct sched_param prio;
    pthread_attr_t attr;

    pthread_t tid1;
    pthread_t tid2;

    policy = SCHED_OTHER;
    if (pthread_setschedparam( pthread_self(),policy, &prio )){
        perror ("Error: pthread_setschedparam (root permission?)");
        exit(1);
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_FIFO;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 99; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid1, &attr, thread_func, (void *)(1)) ){
        perror ( "Error: pthread1_create" );
        return 1;
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_FIFO;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 1; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid2, &attr, thread_func, (void *)(2)) ){
        perror ( "Error: pthread2_create" );
        return 1;
    }

    /* wait for threads to finish */
    pthread_join ( tid1, NULL );
    pthread_join ( tid2, NULL );

    return 0;
}

If you are interested in how to make an RT Linux, please see another post of mine.

I found a very good material to study deeper on RT thread.

  • https://csperkins.org/teaching/2004-2005/rtes5/lecture10.pdf
  • http://retis.sssup.it/~lipari/courses/str09/10.rtprogramming-handout.pdf

If you have any questions on this code or this post, please leave a reply. Then, good luck!

[1] Nanosleep, http://man7.org/linux/man-pages/man2/nanosleep.2.html

[2] Timespec basic operation, http://www.zemris.fer.hr/~leonardo/srsv/skripta/src/periodic-tasks-2.c

Tutorial: How to make RT Preempt Linux with Ubuntu 18.04.02

In this tutorial, I will present how to make a RT Preempt Linux with Ubuntu 18.04.02

1. install Ubuntu 18.04.02 in your computer. Let me skip the details since there are so many other tutorials for this.

2. Once the install is finished. Download Linux kernel and RT Patch

  • Linux Kernel Download at

https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/

Screenshot from 2020-02-20 23-20-00

  • RT patch download at https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/4.4/

Screenshot from 2020-02-20 23-21-54

3. Prepare to compile the kernel

cd Downloads/
xz -cd linux-4.4.208.tar.xz | tar xvf -
cd linux-4.4.208/
xzcat ../patch-4.4.208-rt191.patch.xz | patch -p1
sudo apt install libncurses5-dev build-essential cmake libssl-dev git flex bison
make menuconfig
  • Set “High Resulution Timer Support” Screenshot from 2020-02-21 00-08-07 Screenshot from 2020-02-21 00-08-13
  • Set “Fully Preemptible Kernel (RT)

Screenshot from 2020-02-21 00-08-47 Screenshot from 2020-02-21 00-09-26 Screenshot from 2020-02-21 00-09-43

  • (optional) set Local version nameScreenshot from 2020-02-21 00-10-24 Screenshot from 2020-02-21 00-10-28
  • Save the config fileScreenshot from 2020-02-21 00-11-08

4. Compile and install the kernel ( WARNING: It takes very long time)

make -j20
sudo make modules_install -j20
sudo make install -j20

Here -jx is to specify the number of CPU cores, if you just choose a high number, it go with your all CPU cores.

5. Grub setting

sudo gedit /etc/default/grub

Then, edit the text as below:

To select the booting option in GRUB

GRUB_TIMEOUT_STYLE=hidden -> GRUB_TIMEOUT_STYLE=menu

To increase the time out for selecting a menu

GRUB_TIMEOUT=0 -> GRUB_TIMEOUT=3

To reduce the visual effect

GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash” -> GRUB_CMDLINE_LINUX_DEFAULT=”quiet”

If you want to boot without graphical desktop (terminal mode)

GRUB_CMDLINE_LINUX=”” -> GRUB_CMDLINE_LINUX=”3″

5. Rebooting

sudo update-grub
sudo reboot

6. Select RT-preempt kernel in GRUB

select Advanced and RT-Linux

(Optional)  If you want to customize GRUB more, then use grub-customizer (grub editor with GUI)

sudo add-apt-repository ppa:danielrichter2007/grub-customizer 
sudo apt update
sudo apt install grub-customizer

Other readings

Now you are ready to develop or run an RT application on RT Preempt Linux. If you need to know how to write a RT thread running with a periodic cycle, read another article of mine.

Good luck!

EsmaCAT: Easy yet powerful robot mechatronics with EtherCAT

EsmaCAT Logo Color

This time I am going to introduce our new product line-up called EsmaCAT developed by Harmonic Bionics.

The EsmaCAT solution allows users easily develop a robotic system without low-level hardware knowledge.

For example, you can control multiple motors while reading analog sensors at faster than 1kHz.

For more info, please visit https://esmacat.com