概述

        分析命令行代码和配置文件之后发现分析了个寂寞,并没有揭开毫米波雷达目标检测的神秘面纱。或许是因为示例工程基于IWR1843,其HWA+DSP的架构允许将处理过程放到HWA中,自然就不会有很多关于处理过程的代码。那就再看看data path相关文档,看看其中有没有我要找的答案。

参考

        《mmwave sdk uer guide》

        《Radar Hardware Accelerator User's Guide》

        《.../packages/tidemo/xwr18xx/mmw/docs/doxygen/html/index.html》

        《.../packages/ti/datapath/dpc/objectdetection/objdethwa/docs/doxygen/html/index.html》

典型处理链路

        典型的毫米波雷达处理链,它接受来自毫米波前端的ADC数据作为输入,然后执行距离和多普勒FFT,然后使用CFAR进行非相干检测。最后,使用3D FFT估计角度,检测到的点表示点云数据。然后,可以使用更高层的算法(如聚类、跟踪、分类)对点云数据进行后处理。

        不同毫米波雷达型号包含不同的处理单元(HWA/DSP/HWA+DSP)来实现毫米波处理,对于具有HWA+DSP的设备(例如IWR1843),毫米波检测处理链可以根据性能和可扩展性的需要利用它们。下图显示了一个检测处理链的示例,该链使用各种数据处理单元(DPU)执行典型的毫米波处理,直至点云。毫米波设备存储器中的毫米波数据表示形成了各种DPU之间的接口层。每个DPU都可以使用HWA或DSP处理节点独立实现——选择取决于用例或给定毫米波设备上该处理节点的可用性。

Data Path

        数据路径时序的顶层示意图如下:

        如时序图所示,数据路径处理被分为两个周期:采集周期和帧间周期。

采集周期

        啁啾期间的处理包括1D(距离)FFT处理,该处理从ADC缓冲器中的多个接收天线获取每个啁啾的输入,并对其执行FFT,并以DPIF_RADARCUBE_format_1定义的格式将输出生成到L3 RAM中。

帧间周期

        啁啾结束到下一个啁啾开始的处理通常包含如下过程,这些

  1. 启用静态杂波去除后,将从场景中删除所有静态对象
  2. 2D(速度)FFT处理,从L3 RAM中的1D输出中获取输入,并执行FFT以在L3 RAM中给出(距离、速度)矩阵。
  3. CFAR处理和峰值分组对多普勒处理的检测矩阵输出。
  4. 到达角度(方位角、仰角)处理,以生成具有位置坐标(x、y、z)和速度的检测对象的最终列表。

应用中如何执行数据处理链

        文档中直接向我们展示了APP-DPC的执行流程,我们对照着代码来看看。

DPM_init

        dss_main.c中看到了DPM_init()函数 ,但仅能追踪到dpm.h文件中的一个声明。

DPC_ObjectDetection_init

        这里发现了DPM_init()函数导致DPC中执行了DPC_ObjectDetection_init()。通过反推,才找到文件“objectdetection.c",在这个文件中实现了相关函数并赋值给结构体DPM_ProcChainCfg。

/**
 * @brief   Global used to register Object Detection DPC in DPM
 */
DPM_ProcChainCfg gDPC_ObjectDetectionCfg =
{
    DPC_ObjectDetection_init,            /* Initialization Function:         */
    DPC_ObjectDetection_start,           /* Start Function:                  */
    DPC_ObjectDetection_execute,         /* Execute Function:                */
    DPC_ObjectDetection_ioctl,           /* Configuration Function:          */
    DPC_ObjectDetection_stop,            /* Stop Function:                   */
    DPC_ObjectDetection_deinit,          /* Deinitialization Function:       */
    NULL,                                /* Inject Data Function:            */
    NULL,                                /* Chirp Available Function:        */
    DPC_ObjectDetection_frameStart       /* Frame Start Function:            */
};

               “objectdetection.h”中包含extern 声明并被“dss_main.c”引用,作为参数的一部分传递给了DPM_init()。

“objectdetection.h”

    /*! Application developers: Use this configuration to load the Object Detection DPC
     *  within the DPM. */
    extern DPM_ProcChainCfg  gDPC_ObjectDetectionCfg;



"dss_main.c"


    #include <ti/datapath/dpc/objectdetection/objdethwa/objectdetection.h>

    /* Setup the configuration: */
    dpmInitCfg.socHandle        = gMmwDssMCB.socHandle;
    dpmInitCfg.ptrProcChainCfg  = &gDPC_ObjectDetectionCfg;
    dpmInitCfg.instanceId       = 0xFEEDFEED;
    dpmInitCfg.domain           = DPM_Domain_REMOTE;
    dpmInitCfg.reportFxn        = MmwDemo_DPC_ObjectDetection_reportFxn;
    dpmInitCfg.arg              = &objDetInitParams;
    dpmInitCfg.argSize          = sizeof(DPC_ObjectDetection_InitParams);

    /* Initialize the DPM Module: */
    gMmwDssMCB.dataPathObj.objDetDpmHandle = DPM_init (&dpmInitCfg, &errCode);

        结构体DPM_ProcChainCfg在"dpm.h"中定义。

/**
 * @brief
 *  Processing Chain Configuration
 *
 * @details
 *  The DPM module is responsible for the registeration and execution of
 *  processing chains. Processing Chains can be created and registered by
 *  populating the following configuration
 */
typedef struct DPM_ProcChainCfg_t
{
    /**
     * @brief   Initialization function:
     */
    DPM_ProcChainInitFxn                      initFxn;

    /**
     * @brief   Start function:
     */
    DPM_ProcChainStartFxn                     startFxn;

    /**
     * @brief   Execute function:
     */
    DPM_ProcChainExecuteFxn                   executeFxn;

    /**
     * @brief   IOCTL function:
     */
    DPM_ProcChainIoctlFxn                     ioctlFxn;

    /**
     * @brief   Stop function:
     */
    DPM_ProcChainStopFxn                      stopFxn;

    /**
     * @brief   Deinitialization function:
     */
    DPM_ProcChainDeinitFxn                    deinitFxn;

    /**
     * @brief   [Optional] Inject Data Function:
     */
    DPM_ProcChainInjectDataFxn                injectDataFxn;

    /**
     * @brief   [Optional] Chirp Available Callback function:
     */
    DPM_ProcChainChirpAvailableCallbackFxn    chirpAvailableFxn;

    /**
     * @brief   [Optional] Frame Start Callback function:
     */
    DPM_ProcChainFrameStartCallbackFxn        frameStartFxn;
}DPM_ProcChainCfg;

        这个API从堆中分配DPC实例和DPU实例(通过调用DPU的初始化API)。

                DPU_RangeProcHWA_init()

                DPU_StaticClutterProc_init()

                DPU_CFARCAProcHWA_init()

                DPU_DopplerProcHWA_init()

                DPU_AoAProcHWA_init()

DPM_execute

        此API在任务MmwDemo_DPC_ObjectDetection_dpmTask()中循环调用,其返回结果显示了有无检测目标。

DPM_ioctl

        此API在"dpm.h"中声明,在“mss_main.c”中被如下函数调用。

  • MmwDemo_DPM_ioctl_blocking()
  • MmwDemo_handleObjectDetResult()
  • MmwDemo_processPendingDynamicCfgCommands()

        注意此函数在流程中多次调用并传递了不同参数:

  • DPC_OBJDET_IOCTL__STATIC_PRE_START_COMMON_CFG
  • DPC_OBJDET_IOCTL__STATIC_PRE_START_CFG

 DPC_ObjectDetection_ioctl

        此函数与DPC_ObjectDetection_init一同作为参数传递给DPM_init。可以通过DPM_ioctl传递的不同参数(包含子帧索引、预定于的配置等)在此函数中导致不同的配置。但示例中均使用了预启动配置。

        通常如下函数可以被用来进行配置不同的数据处理单元:

  • DPU_RangeProcHWA_config()
  • DPU_StaticClutterProc_config()
  • DPU_CFARCAProcHWA_config()
  • DPU_DopplerProcHWA_config()
  • DPU_AoAProcHWA_config()

ADCBuf配置

        ADCBuf的配置通过命令行工具接收用户指令并执行。

DPM_start

        DPM_start()在Demo中的调用过程如下:

  1. 用户通过命令行工具输入指令“sensorStart”,命令行工具调用MmwDemo_CLISensorStart()
  2. MmwDemo_CLISensorStart()中调用MmwDemo_startSensor()
  3. MmwDemo_startSensor()中调用MmwDemo_dataPathStart()
  4. MmwDemo_dataPathStart()中调用DPM_start()

DPC_ObjectDetection_start

        此函数与DPC_ObjectDetection_init一同作为参数传递给DPM_init。此函数会触发距离数据处理单元DPU_RangeProcHWA_control()。

DPC_ObjectDetection_frameStart

        此函数与DPC_ObjectDetection_init一同作为参数传递给DPM_init,DPC帧起始函数,调用DPM_notifyExecute()告知DPM模块DPC已就绪。        

        DPM_ioctl传递DPC_OBJDET_IOCTL__TRIGGER_FRAME参数以模拟触发,或RF前端接收到帧起始ISR时调用此函数。

DPC_ObjectDetection_execute

        此函数与DPC_ObjectDetection_init一同作为参数传递给DPM_init,DPC帧数据处理函数。

        当DPC_ObjectDetection_frameStart发出DPM_notifyExecute时,应用程序在DPM的执行上下文中调用该函数,该函数在每次帧中断时调用。

        如下处理函数通常会被调用来处理数据:

  • DPU_RangeProcHWA_process()
  • DPU_StaticClutterProc_process()
  • DPU_DopplerProcHWA_config()
  • DPU_DopplerProcHWA_process()
  • DPU_CFARCAProcHWA_config()
  • DPU_CFARCAProcHWA_process()
  • DPU_AoAProcHWA_config()
  • DPU_AoAProcHWA_process()

总结

        至此我们已经获得了足够的数据,后续就是数据的后处理,针对不同的应用场景和需求筛选出需要的目标了。

        分析完命令行代码和数据路径之后,再看毫米波雷达的应用框图和SDK层级示意图就具体多了。虽然暂时还达不到一切细节了然于胸,但是继续前行的道路已经显现,只要后续不断学习深入,毫米波雷达程序开发肯定会越来越得心应手。

        到目前为止仅仅是让毫米波雷达工作起来,满足了功能要求:检测到了目标,获取了目标的距离、速度、角度等数据。但是这些数据满足我们的性能要求吗?out of box示例和high accuracy的测距精度为什么不一样?看来还得研究研究神秘的啁啾(chirp)。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐