簡體   English   中英

程序調用延遲 - C&Linux

[英]Program call delay - 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程序),我們意識到它沒有按照我們想要的那樣快速執行。

為了復制和隔離問題,我寫了一個shell腳本(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"

每個功能之間有14ms的延遲(用示波器測量)。 我做了很多小實驗來解決這個問題。 打開和關閉SPI端口,發送SPI命令和解析agv []不是問題。 如果我在同一個程序中多次調用它們,則每個串行數據包之間的延遲大約為700us。

調用“nice -n -19 ./fxa_test_z_1”沒有改變任何東西。

==

我該怎么做才能使這些函數調用更快? 有什么希望我可以讓他們去sub-ms?

現在我正試圖避免對我的代碼進行重大修改,因為我們希望明天測試我們的控制循環。

謝謝!

傑夫

您可以通過讓plan在必須再次運行之前完成更多工作來加快速度。 開始一個過程需要做很多工作,所以你不想經常這么做。

要使plan做更多工作,您可以在stdin或文件中提供命令列表。 然后棘手的部分是解析每一行以提取單獨的命令和參數。 由於您的現有代碼已經從argv讀取命令,因此使用strtok將命令解析為類似argv的數組很容易:

#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個命令。

我將indiv的代碼與我的main()合並,它可以工作,我可以每760us發送一個新命令(比以前快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;
}

我的測試shell腳本是:

#!/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

非常感謝您的幫助!

傑夫

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM