Задержка вызова программы — C и Linux

Я работаю над новым оборудованием для активных протезов ног. В моей системе есть встроенный компьютер BeagleBone Black RevC и несколько нестандартных плат. BeagleBone Black (BBB) ​​работает под управлением Debian Linux.

Я написал консольное приложение C, чтобы общаться с другими платами из Linux. С терминала я могу отправить команду типа «./plan execute_1 set_pid_gains 10 50 0», чтобы изменить коэффициенты усиления контура управления, работающего на моем драйвере двигателя. Функция «план» написана на C. Она отправляет сообщение через SPI.

Программа отлично работает сама по себе, я могу отправить все команды, которые хочу. Однако когда мы начали тестировать его из Python (используя Popen для вызова программы на C), мы поняли, что он выполняется не так быстро, как хотелось бы.

Чтобы воспроизвести и изолировать проблему, я написал сценарий оболочки (fxa_test_z_1), который отправляет в мою сеть 3 команды:

#!/bin/bash
# Places FlexSEA in Impedance control mode
# Use with care!

# Set control mode to 'z' (4)
./plan execute_1 set_control 4

# Current loop gains:
./plan execute_1 set_current_gains 10 50 0

# Choose from one of these:
./plan execute_1 set_z_gains 1 0 0
echo "FlexSEA in Stiffness mode"

Между каждой функцией есть задержка 14 мс (измеренная с помощью осциллографа). Я провел много небольших экспериментов, чтобы изолировать проблему. Открытие и закрытие порта SPI, отправка команд SPI и анализ agv[] не являются проблемой. Если я вызываю их несколько раз в одном вызове программы, задержка составляет порядка 700 мкс между каждым последовательным пакетом.

Вызов «nice -n -19 ./fxa_test_z_1» ничего не изменил.

==

Что я могу сделать, чтобы эти вызовы функций выполнялись быстрее? Есть ли надежда, что я смогу заставить их стать субмс?

Прямо сейчас я стараюсь не вносить серьезные изменения в свой код, так как завтра мы хотим протестировать наши циклы управления.

Спасибо!

Джефф


person JFDuval    schedule 12.08.2014    source источник
comment
Это не функции, которые вы вызываете. Вы запускаете совершенно новый процесс для запуска автономной программы под названием plan. Создание процесса происходит медленно. Вместо этого вы хотели бы иметь цикл plan на стандартном вводе или файл, читающий каждую команду одну за другой, чтобы plan не приходилось разрывать и перезапускать для каждой команды.   -  person indiv    schedule 13.08.2014
comment
Спасибо индив! Я знаю, что запускаю новый процесс, а не функцию, но все это программное обеспечение для меня новое, поэтому я не был уверен, как работать с несколькими командами в одном вызове программы. Кажется, это то, что мне нужно, верно? stackoverflow.com/questions/9157222/c-wait-for-stdin-read   -  person JFDuval    schedule 13.08.2014
comment
В качестве альтернативы преобразуйте свою программу C в расширение Python.   -  person Deduplicator    schedule 13.08.2014


Ответы (2)


Вы можете сделать это быстрее, заставив plan выполнить больше работы, прежде чем его нужно будет запустить снова. Запуск процесса требует много работы, поэтому не стоит делать это чаще, чем необходимо.

Чтобы plan выполнял больше работы, вы можете передать ему список команд из стандартного ввода или из файла. Хитрость заключается в анализе каждой строки для извлечения отдельных команд и параметров. Поскольку ваш существующий код уже считывает команды из argv, достаточно просто разобрать команды в массив, подобный argv, используя strtok:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_COMMAND_LEN 256
#define MAX_ARGS 64
char *fake_argv[MAX_ARGS];  /* For compatibility with existing parser. */
const char *delims = " \n";

int main(int argc, char *argv[])
{
    char command[MAX_COMMAND_LEN];

    while( fgets(command, sizeof(command), stdin) )
    {
        int fake_argc = 0;
        fake_argv[fake_argc] = strtok(command, delims);
        while( fake_argv[fake_argc] != NULL )
        {
            fake_argv[++fake_argc] = strtok(NULL, delims);      
        }

        { int i;  /* debug print... you can remove this block */
          printf("Handling command: [%s], argc %d\n", command, fake_argc);
          for( i = 0; i < fake_argc; ++i ) { printf("  arg: [%s]\n", fake_argv[i]); }
        }
        /* ... do the stuff you were already doing except now with fake_argv */
    }

    return 0;
}

Тогда ваш сценарий bash может быть просто набором строк, которые вы вводите в свою программу:

./plan << END_COMMAND_LIST
execute_1 set_control 4
execute_1 set_current_gains 10 50 0
execute_1 set_z_gains 1 0 0
END_COMMAND_LIST

Теперь процесс plan создается один раз и выполняет 3 команды перед выходом.

person indiv    schedule 13.08.2014
comment
Надеюсь, поможет. Я забыл заполнить fake_argv[0], поэтому ваши индексы могут отличаться на 1. - person indiv; 13.08.2014

Я объединил код indiv с моим main(), и он работает, я могу отправлять новые команды каждые 760 мкс (в 18 раз быстрее, чем раньше!)

Мой код может быть не таким элегантным, но другим может быть полезно полное решение, так что вот оно:

//****************************************************************************
// main: FlexSEA Plan project: console app to control FlexSEA slaves
//****************************************************************************

//****************************************************************************
// Include(s)
//****************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../inc/flexsea_console.h"
#include "../inc/plan_spi.h"
#include "flexsea_local.h"

//****************************************************************************
// Local variable(s) & definitions
//****************************************************************************

int analog0 = 0;

//Choose between single multiple commands console app:
//#define SINGLE_COMMAND
#define MULTIPLE_COMMANDS

#ifdef SINGLE_COMMAND
    #ifdef MULTIPLE_COMMANDS
        #error "Pick one Command option!"
    #endif
#endif


#define MAX_COMMAND_LEN 256
#define MAX_ARGS 8
char *fake_argv[MAX_ARGS];
const char *delims = " \n";

//****************************************************************************
// External variable(s)
//****************************************************************************

extern unsigned char execute_1_data[];

//****************************************************************************
// Function(s)
//****************************************************************************

int main(int argc, char *argv[])
{
    #ifdef MULTIPLE_COMMANDS
    char command[MAX_COMMAND_LEN];
    char string1[20], string2[20] = "quit";
    char default_argv[] = "";
    int i = 0;
    #endif  //MULTIPLE_COMMANDS

    //Open SPI:
    flexsea_spi_open();

    #ifdef MULTIPLE_COMMANDS
    while(fgets(command, sizeof(command), stdin))
    {
        int fake_argc = 1;

        //Fills fake_argv with empty strings to avoid sending old values with new commands
        for(i = 0; i < MAX_ARGS; i++)
        {
            fake_argv[i] = default_argv;
        }

        //First argument
        fake_argv[fake_argc] = strtok(command, delims);

        //Other arguments
        while( fake_argv[fake_argc] != NULL )
        {
            fake_argv[++fake_argc] = strtok(NULL, delims);
        }

        //Enable for terminal debug only:
        /*
        for(i = 0; i < MAX_ARGS; i++)
        {
            printf("fake_argv[%i] = %s\n", i, fake_argv[i]);
        }
        */

        //Do we want to exit? (exit when "quit" is received)
        strcpy(string1, fake_argv[1]);
        if(!strcmp(string1, string2))
        {
            printf("Quitting.\n");
            break;
        }
        else
        {
            //Parser for console commands:
            flexsea_console_parser(fake_argc, fake_argv);

            //Can we decode what we received?
            decode_spi_rx();
        }
    }
    #endif  //MULTIPLE_COMMANDS

    #ifdef SINGLE_COMMAND

    //Parser for console commands:
    flexsea_console_parser(argc, argv);

    //Can we decode what we received?
    decode_spi_rx();

    #endif  //SINGLE_COMMAND

    //Close SPI:
    flexsea_spi_close();

    return 0;
}

Мой сценарий тестовой оболочки:

#!/bin/bash
# How quickly can we send serial commands?

./plan << END_COMMAND_LIST
execute_1 set_leds 0 255 0 0
execute_1 set_leds 0 255 0 0
execute_1 set_leds 0 255 0 0
execute_1 set_leds 0 255 0 0
execute_1 set_leds 0 255 0 0
END_COMMAND_LIST

Большое спасибо за помощь!

Джефф

person JFDuval    schedule 13.08.2014