1. Anuncie Aqui ! Entre em contato fdantas@4each.com.br

[Python] The invocation of C++ by Supervisor fails

Discussão em 'Python' iniciado por Stack, Setembro 12, 2024.

  1. Stack

    Stack Membro Participativo

    The invocation of C++ by Supervisor fails.


    Operating system environment:

    1. Jetpack 6.0.
    2. Ubuntu 22.04.
    3. aarch64.

    First, I have a C++ program for a Hikvision industrial camera. It calls the XOpenDisplay function of the X11 library to start a window and display the video stream of the camera. After compiling it, using ./Display or /bin/bash -c "/opt/MVS/Samples/aarch64/Display/Display" in the terminal can both start the window and see the video stream. Next, I encapsulated it using the following Python code to provide an API for access. After starting the FastAPI service through the following command /usr/bin/python /root/main.py in the terminal, accessing this API can also normally start the window and see the video stream.

    However, when I assign the task of starting the FastAPI web service to supervisor. After starting the web service normally, calling the API service prompts please run with screen environment. It can be found that an execution error occurs on the line of code dpy = XOpenDisplay(NIL);, which causes it to output the prompt.

    Finally, what should I do to enable the Python application managed by supervisor to call the C++ compiled program normally using subprocess?

    Attempts made:


    1. Add environment variables, such as DISPLAY=:0.


    2. Output the value of the current environment variable DISPLAY as :0 inside Dispaly.cpp to confirm that the environment variable is correct.


    3. Ensure that the code for starting the Python script is a shell script and use the supervisor configuration of command=/bin/bash -c "/usr/bin/python /path/to/my/python/main.py", but it still doesn't work.


    4. Use xhost + to allow all the user can connect to X server.
    The following is the FastAPI web code(main.py).


    from fastapi import FastAPI
    import subprocess as sp
    app = FastAPI()


    @app.get('/test_hik')
    def test_hik():
    cmd = f'/bin/bash -c "/path/to/the/Display"'
    import os
    # sp.call(cmd, shell=True, cwd = config.DISPLAY_PATH.parent, env=dict(os.environ, DISPLAY=":0", XAUTHORITY="/home/jetson/.xsessionrc"))
    sp.call(cmd, shell=True, cwd = config.DISPLAY_PATH.parent)
    return {'status':True, 'msg':'Success start window grab images...'}


    if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app)

    The following is the supervisor configuration.


    [program:pollen]
    autorestart=True
    autostart=True
    redirect_stderr=True
    command=/bin/bash -c "DISPLAY=:0 /bin/bash /path/to/my/python/main.sh"
    user=root
    directory=/root/pollen_new
    stdout_logfile_maxbytes=20MB
    stdout_logfile_backups=20
    stdout_logfile=/var/log/pollen.log
    environment=DISPLAY=":0",MVCAM_SDK_PATH="/opt/MVS",MVCAM_COMMON_RUNENV="/opt/MVS/lib",MVCAM_GENICAM_CLPROTOCOL="/opt/MVS/lib/CLProtocol",ALLUSERSPROFILE="/opt/MVS/MVFG"

    The following is the Display C++ codes.


    #include <X11/Xlib.h>
    #include <assert.h>
    #include "math.h"

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include "MvCameraControl.h"

    #define NIL (0)

    bool g_bExit = false;
    Window g_hwnd;

    // 等待用户输入enter键来结束取流或结束程序
    // wait for user to input enter to stop grabbing or end the sample program
    void PressEnterToExit(void)
    {
    int c;
    while ( (c = getchar()) != '\n' && c != EOF );
    fprintf( stderr, "\nPress enter to exit.\n");
    while( getchar() != '\n');
    g_bExit = true;
    sleep(1);
    }

    bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
    {
    if (NULL == pstMVDevInfo)
    {
    printf("The Pointer of pstMVDevInfo is NULL!\n");
    return false;
    }
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
    {
    int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
    int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
    int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
    int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

    // ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined name
    printf("Device Model Name: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);
    printf("CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
    printf("UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
    }
    else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
    {
    printf("Device Model Name: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);
    printf("UserDefinedName: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
    }
    else
    {
    printf("Not support.\n");
    }

    return true;
    }

    static void* WorkThread(void* pUser)
    {
    int nRet = MV_OK;
    MV_FRAME_OUT stImageInfo = {0};
    MV_DISPLAY_FRAME_INFO stDisplayInfo = {0};

    while(1)
    {
    nRet = MV_CC_GetImageBuffer(pUser, &stImageInfo, 1000);
    if (nRet == MV_OK)
    {
    //printf("Get Image Buffer: Width[%d], Height[%d], FrameNum[%d]\n", stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);

    if (g_hwnd)
    {
    stDisplayInfo.hWnd = (void*)g_hwnd;
    stDisplayInfo.pData = stImageInfo.pBufAddr;
    stDisplayInfo.nDataLen = stImageInfo.stFrameInfo.nFrameLen;
    stDisplayInfo.nWidth = stImageInfo.stFrameInfo.nWidth;
    stDisplayInfo.nHeight = stImageInfo.stFrameInfo.nHeight;
    stDisplayInfo.enPixelType = stImageInfo.stFrameInfo.enPixelType;

    MV_CC_DisplayOneFrame(pUser, &stDisplayInfo);
    }

    nRet = MV_CC_FreeImageBuffer(pUser, &stImageInfo);
    if(nRet != MV_OK)
    {
    printf("Free Image Buffer fail! nRet [0x%x]\n", nRet);
    }
    }
    else
    {
    printf("Get Image fail! nRet [0x%x]\n", nRet);
    }
    if(g_bExit)
    {
    break;
    }
    }

    return 0;
    }

    int main()
    {
    Display *dpy;

    memset(&g_hwnd, 0, sizeof(Window));
    dpy = NULL;

    // 打开连接到X服务器的连接
    // open the connection to the display 0
    dpy = XOpenDisplay(NIL);

    if (NULL == dpy)
    {
    printf("please run with screan environment\n");
    return -1;
    }

    int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));

    g_hwnd = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
    752, 480, 0, 0xffff00ff, 0xff00ffff);

    // 获取改变窗口大小事件
    // we want to get MapNotify events
    XSelectInput(dpy, g_hwnd, StructureNotifyMask |ExposureMask | KeyPressMask);

    // 使窗口可见
    // "Map" the window (that is, make it appear on the screen)
    XMapWindow(dpy, g_hwnd);

    // 创建图像上下文给出绘图函数的属性
    // Create a "Graphics Context"
    GC gc = XCreateGC(dpy, g_hwnd, 0, NIL);

    // 告诉GC使用白色
    // Tell the GC we draw using the white color
    XSetForeground(dpy, gc, whiteColor);

    // 等待事件的到来
    // Wait for the MapNotify event
    for(;;)
    {
    XEvent e;
    XNextEvent(dpy, &e);
    if (e.type == MapNotify)
    {
    break;
    }
    }

    int nRet = MV_OK;

    void* handle = NULL;
    do
    {
    MV_CC_DEVICE_INFO_LIST stDeviceList;
    memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));

    // 枚举设备
    // enum device
    nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    if (MV_OK != nRet)
    {
    printf("MV_CC_EnumDevices fail! nRet [%x]\n", nRet);
    break;
    }

    if (stDeviceList.nDeviceNum > 0)
    {
    for (int i = 0; i < stDeviceList.nDeviceNum; i++)
    {
    printf("[device %d]:\n", i);
    MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo;
    if (NULL == pDeviceInfo)
    {
    break;
    }
    PrintDeviceInfo(pDeviceInfo);
    }
    }
    else
    {
    printf("Find No Devices!\n");
    break;
    }

    // printf("Please Intput camera index: ");
    unsigned int nIndex = 0;
    // scanf("%d", &nIndex);

    if (nIndex >= stDeviceList.nDeviceNum)
    {
    printf("Intput error!\n");
    break;
    }

    // 选择设备并创建句柄
    // select device and create handle
    nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
    if (MV_OK != nRet)
    {
    printf("MV_CC_CreateHandle fail! nRet [%x]\n", nRet);
    break;
    }

    // 打开设备
    // open device
    nRet = MV_CC_OpenDevice(handle);
    if (MV_OK != nRet)
    {
    printf("MV_CC_OpenDevice fail! nRet [%x]\n", nRet);
    break;
    }

    // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
    if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
    {
    int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
    if (nPacketSize > 0)
    {
    nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
    if(nRet != MV_OK)
    {
    printf("Warning: Set Packet Size fail nRet [0x%x]!\n", nRet);
    }
    }
    else
    {
    printf("Warning: Get Packet Size fail nRet [0x%x]!\n", nPacketSize);
    }
    }


    // 设置float型变量
    // set IFloat variable
    float fAcquisitionFrameRate = 20.0f;

    nRet = MV_CC_SetFloatValue(handle, "AcquisitionFrameRate", fAcquisitionFrameRate);
    if (MV_OK == nRet)
    {
    printf("set AcquisitionFrameRate OK!\n\n");
    }
    else
    {
    printf("set AcquisitionFrameRate failed! nRet [%x]\n\n", nRet);
    }

    // 设置int型变量 height
    // set IInteger variable
    unsigned int nHeightValue = 1080;

    // 宽高设置时需考虑步进(16),即设置宽高需16的倍数
    // Step (16) should be considered when setting width and height, that is the width and height should be a multiple of 16
    nRet = MV_CC_SetIntValue(handle, "Height", nHeightValue);
    if (MV_OK == nRet)
    {
    printf("set height OK!\n\n");
    }
    else
    {
    printf("set height failed! nRet [%x]\n\n", nRet);
    }

    unsigned int nWidthValue = 1440;

    // 宽高设置时需考虑步进(16),即设置宽高需16的倍数
    // Step (16) should be considered when setting width and height, that is the width and height should be a multiple of 16
    nRet = MV_CC_SetIntValue(handle, "Width", nWidthValue);
    if (MV_OK == nRet)
    {
    printf("set width OK!\n\n");
    }
    else
    {
    printf("set width failed! nRet [%x]\n\n", nRet);
    }

    // 设置bool型变量
    // set IBoolean variable
    bool bAcquisitionFrameRateEnable = true;
    nRet = MV_CC_SetBoolValue(handle, "AcquisitionFrameRateEnable", bAcquisitionFrameRateEnable);
    if (MV_OK == nRet)
    {
    printf("Set AcquisitionFrameRateEnable OK!\n\n");
    }
    else
    {
    printf("Set AcquisitionFrameRateEnable Failed! nRet = [%x]\n\n", nRet);
    }

    // 设置enum型变量 ExposureAuto
    // set IEnumeration variable
    unsigned int nExposureAuto = 2;//Continuous
    nRet = MV_CC_SetEnumValue(handle, "ExposureAuto", nExposureAuto);
    if (MV_OK == nRet)
    {
    printf("set ExposureAuto OK!\n\n");
    }
    else
    {
    printf("set ExposureAuto failed! nRet [%x]\n\n", nRet);
    }


    // 设置int型变量 AutoExposureTimeUpperLimit
    // set IInteger variable
    unsigned int nAutoExposureTimeUpperLimit = 25000;
    nRet = MV_CC_SetIntValue(handle, "AutoExposureTimeUpperLimit", nAutoExposureTimeUpperLimit);
    if (MV_OK == nRet)
    {
    printf("set AutoExposureTimeUpperLimit OK!\n\n");
    }
    else
    {
    printf("set AutoExposureTimeUpperLimit failed! nRet [%x]\n\n", nRet);
    }



    // 开始取流
    // start grab image
    nRet = MV_CC_StartGrabbing(handle);
    if (MV_OK != nRet)
    {
    printf("MV_CC_StartGrabbing fail! nRet [%x]\n", nRet);
    break;
    }

    pthread_t nThreadID;
    nRet = pthread_create(&nThreadID, NULL ,WorkThread , handle);
    if (nRet != 0)
    {
    printf("thread create failed.ret = %d\n",nRet);
    break;
    }

    XEvent event;

    fprintf( stderr, "\nPress q to exit.\n");
    while (1) {
    XNextEvent(dpy, &event);
    if (event.type == Expose) {
    // Draw or redraw the window here
    } else if (event.type == KeyPress) {
    KeySym keysym = XLookupKeysym(&event.xkey, 0);
    if (keysym == 'q') {
    printf("Quitting...\n");
    g_bExit = true;

    break;
    }
    }

    sleep(1);
    }




    // PressEnterToExit();

    // 停止取流
    // stop grab image
    nRet = MV_CC_StopGrabbing(handle);
    if (MV_OK != nRet)
    {
    printf("MV_CC_StopGrabbing fail! nRet [%x]\n", nRet);
    break;
    }

    // 关闭设备
    // close device
    nRet = MV_CC_CloseDevice(handle);
    if (MV_OK != nRet)
    {
    printf("MV_CC_CloseDevice fail! nRet [%x]\n", nRet);
    break;
    }

    // 销毁句柄
    // destroy handle
    nRet = MV_CC_DestroyHandle(handle);
    if (MV_OK != nRet)
    {
    printf("MV_CC_DestroyHandle fail! nRet [%x]\n", nRet);
    break;
    }
    handle = NULL;
    }while (0);


    if (handle != NULL)
    {
    MV_CC_DestroyHandle(handle);
    handle = NULL;
    }
    printf("exit.\n");

    return 0;
    }

    Continue reading...

Compartilhe esta Página