Как запланировать циклическую задачу в реальном времени?

Мы — команда студентов бакалавриата, которые в настоящее время работают над созданием робота на ногах. На данный момент наш интерфейс к роботу написан на питоне с использованием SDK от основной платы, которую мы используем.

Для связи с мастер-платой sdk нам нужно отправлять команду каждую миллисекунду.

Чтобы позволить нам периодически отправлять задачи, мы применили патч rt-preempt к нашему ядру Linux. (Ubuntu LTS 20.04, ядро ​​5.10.27-rt36)

Мы очень новичок в написании приложений реального времени и столкнулись с некоторыми проблемами, когда наша задача иногда будет иметь гораздо меньший временной шаг, чем указано. На рисунке ниже мы отобразили время каждого цикла цикла while, когда команда отправляется в SDK. (ось x — это время в секундах, а ось y — прошедшее время итерации, также в секундах). Как видно на графике, один шаг намного меньше остальных. Кажется, это происходит в одну и ту же отметку времени каждый раз, когда мы запускаем скрипт.

cyclo_task_plot

Мы устанавливаем приоритет всего скрипта, используя:

pid = os.getpid()
sched = os.SCHED_FIFO
param = os.sched_param(98)
os.sched_setscheduler(pid, sched, param)

Наша циклическая задача выглядит так:

дт установлен на 0,001

while(_running):
    if direction:
        q = q + 0.0025
        if (q > np.pi/2).any():
            direction = False
    else:
        q = q - 0.0025
        if (q < -np.pi/2).any():
            direction = True

    master_board.track_reference(q, q_prime)


    #Terminate if duration has passed
    if (time.perf_counter() - program_start > duration):
        _running = False

    cycle_time = time.perf_counter() - cycle_start
    time.sleep(dt - cycle_time)
    cycle_start = time.perf_counter()

    timestep_end = time.perf_counter()
    time_per_timestep_array.append(timestep_end - timestep_start)
    timestep_start = time.perf_counter()

Мы подозреваем, что проблема связана с тем, как мы определяем количество сна. Cycle_time — это время, затрачиваемое вышеприведенными вычислениями time.sleep(), так что: время сна + время цикла = 1 мс. Однако мы не знаем, как правильно это сделать, и изо всех сил пытаемся найти ресурсы по этому вопросу.

Как правильно определить задачу, подобную этой, для приложения реального времени?

У нас достаточно свободные требования (несколько миллисекунд), но нам очень важно, чтобы оно было детерминированным, так как это часть нашего тезиса и нам нужно понимать, что происходит.

Будем очень признательны за любые ответы на наш вопрос или соответствующие ресурсы.

Ссылка на полный код: https://drive.google.com/drive/folders/12KE0EBaLc2rkTZK2FuX_goMF4MgWtknS?usp=sharing


person kevinAlfsen    schedule 16.04.2021    source источник


Ответы (1)


    timestep_end = time.perf_counter()
    time_per_timestep_array.append(timestep_end - timestep_start)
    timestep_start = time.perf_counter()

Вы записываете время между timestep_start предыдущего цикла и timestep_end текущего цикла. Этот интервал не точно представляет шаг времени цикла (даже если предположить, что вытеснение задачи не происходит); это исключает время, затрачиваемое функцией добавления массива. Поскольку выброс, похоже, происходит в одну и ту же отметку времени каждый раз, когда мы запускаем скрипт, мы можем предположить, что в этот момент массив превышает определенный размер, когда должно происходить дорогостоящее перераспределение памяти. Независимо от реальной причины, вы должны устранить такие неточности синхронизации, записав время между запусками цикла:

    timestep_end = cycle_start
    time_per_timestep_array.append(timestep_end - timestep_start)
    timestep_start = cycle_start
person Armali    schedule 16.04.2021