nvidia-drive-PX2中lidar_accumulator学习笔记

笔者最近在开发PX2和velodyne-HDL-64,前些天通过PX2中自带的数据采集例子采集了激光雷达的点云数据。现在学习一下自带demo中的lidar_accumulator例子。

先贴一下代码:

#include <iostream>
#include <signal.h>
#include <string.h>

#include <chrono>
#include <memory>
#include <thread>
#include <map>
#include <algorithm>

#include <VersionCurrent.h>
#include <DriveWorksSample.hpp>
#include <SampleFramework.hpp>
#include <SimpleCamera.hpp>
#include <SimpleStreamer.hpp>
#include <WindowGLFW.hpp>
#include <MathUtils.hpp>

// CORE
#include <dw/renderer/RenderEngine.h>
#include <dw/image/ImageStreamer.h>

// SAL
#include <dw/sensors/Sensors.h>
#include <dw/sensors/lidar/Lidar.h>
#include <dw/lidaraccumulator/LidarAccumulator.h>

using namespace dw_samples::common;
using namespace dw::common;

/// @brief Creates a color from an array of floats
///        This allows the constants from the dwRenderer to be used with the dwRendererEngine directly.
inline dwVector4f dwColorFromArray(const float32_t array[4])
{
    dwVector4f res;
    res.x = array[0];
    res.y = array[1];
    res.z = array[2];
    res.w = array[3];
    return res;
}

class LidarAccumulator : public DriveWorksSample    //前者继承后耿{
private:
    // ------------------------------------------------
    // Driveworks Context and SAL
    // ------------------------------------------------
    dwContextHandle_t               context             = DW_NULL_HANDLE;
    dwSALHandle_t                   sal                 = DW_NULL_HANDLE;

    // ------------------------------------------------
    // Sample specific variables
    // ------------------------------------------------
    dwSensorHandle_t           lidarSensor          = DW_NULL_HANDLE;
    dwImageStreamerHandle_t    image2Gl             = DW_NULL_HANDLE;

    dwRenderEngineHandle_t     renderEngine         = DW_NULL_HANDLE;

    dwLidarAccumulatorHandle_t fullLidarAccumulator = DW_NULL_HANDLE;
    dwLidarAccumulatorHandle_t sectLidarAccumulator = DW_NULL_HANDLE;

    dwLidarProperties          lidarProperties{};

    dwLidarAccumulatorBuffer   fullLidarBuffer{};
    dwLidarAccumulatorBuffer   sectLidarBuffer{};

    float32_t minAngle;
    float32_t maxAngle;
    float32_t minDistance;
    float32_t maxDistance;
    float32_t deltaSpinAngle = 0;

    dwImageHandle_t fullLidarImage = DW_NULL_HANDLE;
    dwImageHandle_t sectLidarImage = DW_NULL_HANDLE;
    std::unique_ptr<dwLidarPointXYZI[]> hXYZI;

    dwLidarImageType lidarImageType;

    std::vector<std::string> supportedLidarDevices =
                                         {"VELO_HDL64E", "VELO_HDL32E",
                                          "VELO_VLP32C", "VELO_VLP16HR",
                                          "VELO_VLP16", "QUAN_M81A"};

    bool recordedLidar = false;
    uint32_t tileId[2];
    uint32_t renderBufferId[2];
    uint32_t validCount = 0;
    const uint32_t FULL_SPIN = 0;
    const uint32_t SECT_SPIN = 1;

    std::string strTop;
    std::string strBottom;
    uint32_t spinCount = 0;
    bool bMultiThreaded = false;
    std::thread loadThread;

public:
    LidarAccumulator(const ProgramArguments& args) : DriveWorksSample(args) {}
    ///ǰ֟˽Ԑ݌Ԑ۳֟?    /// -----------------------------
    /// Initialize Render Engine, Sensors, Image Streamers and Tracker
    /// -----------------------------
    bool onInitialize() override
    {
        // -----------------------------------------
        // Initialize DriveWorks context and SAL
        // -----------------------------------------
        {
            // initialize logger to print verbose message on console in color
            dwLogger_initialize(getConsoleLoggerCallback(true)); //Եʼۯɕ־݇¼Ƿ
            dwLogger_setLogLevel(DW_LOG_VERBOSE);  //ʨ׃ɕ־ԢզȫҿɟԠхϢ

            // initialize SDK context, using data folder
            dwContextParameters sdkParams = {};  //֨ӥһٶӎ˽ޡٹͥ
            sdkParams.dataPath = DataPath::get_cstr(); //ʨ׃dataPathΪ˽ߝզԢַ֘

#ifdef VIBRANTE
            sdkParams.eglDisplay = getEGLDisplay();
#endif

            dwInitialize(&context, DW_VERSION, &sdkParams);//Եʼۯdriveworks
            dwSAL_initialize(&sal, context); //ԵʼۯԫِǷSAL
        }

        // -----------------------------
        // initialize sensors
        // -----------------------------
        initSensor();

        // -----------------------------
        // initialize lidar accumulator
        // -----------------------------
        initLidarAccumulators();

        // -----------------------------
        // Initialize Render Engine
        // -----------------------------
        initRenderer();

        // -----------------------------
        // initialize streamer pipeline
        // -----------------------------
        {
            dwImageProperties prop{};
            dwImage_getProperties(&prop, fullLidarImage);
            if ((prop.width > 0) && (prop.height > 0)) {
                CHECK_DW_ERROR(dwImageStreamer_initialize(&image2Gl, &prop, DW_IMAGE_GL, context));
            }
        }

        // -----------------------------
        // start load packet thread if necessary
        // -----------------------------
        bMultiThreaded = (getArgument("mode") == "async" ? true : false);
        if (bMultiThreaded) {
            loadThread = std::thread([&]() {
                while(shouldRun()) {
                    const dwLidarDecodedPacket *nextPacket;
                    dwStatus status = dwSensorLidar_readPacket(&nextPacket, 1000, lidarSensor);
                    if (status == DW_SUCCESS) {                         
                        dwLidarAccumulator_addPacket(nextPacket, fullLidarAccumulator);
                        CHECK_DW_ERROR(dwSensorLidar_returnPacket(nextPacket, lidarSensor));
                    }
                    else if (status == DW_END_OF_STREAM) {
                        reset();
                    }
                }
            });
        }

        getMouseView().setRadiusFromCenter(50.f);
        return true;
    }

    ///------------------------------------------------------------------------------
    /// Release acquired memory
    ///------------------------------------------------------------------------------
    void onRelease() override
    {
        if (bMultiThreaded && loadThread.joinable()) {
            loadThread.join();
        }

        dwSensor_stop(lidarSensor);

        dwImage_destroy(&fullLidarImage);
        dwImage_destroy(&sectLidarImage);

        dwLidarAccumulator_release(&fullLidarAccumulator);
        dwLidarAccumulator_release(&sectLidarAccumulator);

        dwSAL_releaseSensor(&lidarSensor);
        dwImageStreamer_release(&image2Gl);

        // release used objects in correct order
        dwRenderEngine_destroyBuffer(renderBufferId[FULL_SPIN], renderEngine);
        dwRenderEngine_destroyBuffer(renderBufferId[SECT_SPIN], renderEngine);
        dwRenderEngine_release(&renderEngine);

        // -----------------------------------------
        // Release DriveWorks handles, context and SAL
        // -----------------------------------------
        {
            dwLogger_release();
            dwSAL_release(&sal);
            dwRelease(&context);
        }
    }

    void onKeyDown(int key, int /* scancode*/, int /*mods*/) override
    {
        if (key == GLFW_KEY_0)
            lidarImageType = DW_LIDAR_IMAGE_TYPE_INTENSITY_IMAGE;
        // 3D depth Lidar Image
        if (key == GLFW_KEY_1)
            lidarImageType = DW_LIDAR_IMAGE_TYPE_3D_DISTANCE_IMAGE;
        // roll 10 degree counter-clock wise
        if (key == GLFW_KEY_LEFT)
            deltaSpinAngle += 10;
        // roll 10 degree clock wise
        if (key == GLFW_KEY_RIGHT)
            deltaSpinAngle -= 10;
    }

    void onMouseDown(int button, float x, float y, int /*mods*/) override
    {
        getMouseView().mouseDown(button, x, y);
    }

    void onMouseUp(int button, float x, float y, int /*mods*/) override
    {
        getMouseView().mouseUp(button, x, y);
    }

    void onMouseMove(float x, float y) override
    {
        getMouseView().mouseMove(x, y);
    }

    void onMouseWheel(float x, float y) override
    {
        getMouseView().mouseWheel(x, y);
    }

    void onReset() override
    {
        // send an empty packet to Lidar Accumulator
        CHECK_DW_ERROR(dwSensor_reset(lidarSensor));
        CHECK_DW_ERROR(dwLidarAccumulator_reset(fullLidarAccumulator));
        CHECK_DW_ERROR(dwLidarAccumulator_reset(sectLidarAccumulator));
        spinCount = 0;
    }

    ///------------------------------------------------------------------------------
    /// Main processing of the sample
    ///     - grab a frame from the camera
    ///     - convert frame to RGB
    ///     - push frame through the streamer to convert it into GL
    ///     - track the features in the frame
    ///------------------------------------------------------------------------------
    void onProcess() override
    {
        if (!bMultiThreaded)
            pipelineSync();
        else
            pipelineAsync();
    }

    void onRender() override
    {
        if (isOffscreen())
            return;

        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // render 3D lidar points
        {
            dwRenderEngine_setTile(0, renderEngine);
            getMouseView().setWindowAspect(static_cast<float32_t>(getWindowWidth()) / getWindowHeight());

            dwTransformation projection, modelView;
            memcpy(modelView.array, getMouseView().getModelView(), sizeof(dwTransformation));
            memcpy(projection.array, getMouseView().getProjection(), sizeof(dwTransformation));

            dwRenderEngine_setProjection(&projection, renderEngine);
            dwRenderEngine_setModelView(&modelView, renderEngine);

            dwRenderEngine_setColor(dwColorFromArray(DW_RENDERER_COLOR_DARKGREY), renderEngine);
            dwRenderEngine_renderPlanarGrid3D({0, 0, 400, 400}, 5, 5, &DW_IDENTITY_TRANSFORMATION, renderEngine);

            {
                dwRenderEngine_setColor(dwColorFromArray(DW_RENDERER_COLOR_BLUE), renderEngine);
                dwRenderEngine_setPointSize(1.f, renderEngine);
                CHECK_DW_ERROR(dwRenderEngine_renderBuffer(renderBufferId[FULL_SPIN],
                                                           validCount, renderEngine));
            }

            {
                dwRenderEngine_setColor(dwColorFromArray(DW_RENDERER_COLOR_GREEN), renderEngine);
                dwRenderEngine_setPointSize(2.f, renderEngine);
                CHECK_DW_ERROR(dwRenderEngine_renderBuffer(renderBufferId[SECT_SPIN],
                                                           validCount, renderEngine));
            }

            {
                dwRenderEngine_setProjection(&DW_IDENTITY_TRANSFORMATION, renderEngine);
                dwRenderEngine_setModelView(&DW_IDENTITY_TRANSFORMATION, renderEngine);
                dwRenderEngine_setColor(dwColorFromArray(DW_RENDERER_COLOR_ORANGE), renderEngine);

                dwRenderEngine_renderText2D(strTop.c_str(),
                                            {20.f / getWindowWidth(), 40.f / getWindowHeight()},
                                            renderEngine);

                dwRenderEngine_renderText2D(strBottom.c_str(),
                                            {20.f / getWindowWidth(),
                                             1.f - 60.f / getWindowHeight()},
                                            renderEngine);
            }

        }

        // render depth image
        dwRenderEngine_setTile(tileId[FULL_SPIN], renderEngine);
        renderLidarImage(fullLidarImage);

        dwRenderEngine_setTile(tileId[SECT_SPIN], renderEngine);
        renderLidarImage(sectLidarImage);
    }

    //#######################################################################################
    // Run the synchronous pipeline
    // Read Lidar packet and do spin extraction in the same thread
    //#######################################################################################
    void pipelineSync()
    {
        dwStatus sectAccuStatus = DW_NOT_AVAILABLE;
        dwStatus fullAccuStatus = DW_NOT_AVAILABLE;

        while (true) {
            const dwLidarDecodedPacket *nextPacket;
            dwStatus status = dwSensorLidar_readPacket(&nextPacket, 1000, lidarSensor);

            if (status == DW_SUCCESS) {
                {
                    ProfileCUDASection s(getProfilerCUDA(), "AddPacket");
                    fullAccuStatus = dwLidarAccumulator_addPacket(nextPacket, fullLidarAccumulator);
                    sectAccuStatus = dwLidarAccumulator_addPacket(nextPacket, sectLidarAccumulator);
                }

                CHECK_DW_ERROR(dwSensorLidar_returnPacket(nextPacket, lidarSensor));
            }
            else if (status == DW_END_OF_STREAM) {
                reset();
                return;
            }

            else {
                return;
            }

            if (sectAccuStatus == DW_SUCCESS || fullAccuStatus == DW_SUCCESS)
                break;
        }

        // get sector Lidar buffer
        if (sectAccuStatus == DW_SUCCESS) {
            {
                ProfileCUDASection s(getProfilerCUDA(), "getSweep (Sect)");
                CHECK_DW_ERROR(dwLidarAccumulator_getSweep(&sectLidarBuffer, sectLidarAccumulator));
            }

            {
                ProfileCUDASection s(getProfilerCUDA(), "fillImage(Sect)");
                CHECK_DW_ERROR(dwLidarAccumulator_fillImage(sectLidarImage,
                                                            lidarImageType,
                                                            sectLidarAccumulator));
            }

            CHECK_DW_ERROR(dwRenderEngine_setBuffer(
                               renderBufferId[SECT_SPIN], DW_RENDER_ENGINE_PRIMITIVE_TYPE_POINTS_3D,
                               sectLidarBuffer.xyzi, sizeof(dwLidarPointXYZI), 0,
                               sectLidarBuffer.dataCount, renderEngine));

            CHECK_DW_ERROR(dwLidarAccumulator_returnSweep(sectLidarAccumulator));

            CHECK_DW_ERROR(dwLidarAccumulator_setAngleSpan(minAngle + deltaSpinAngle,
                                                           maxAngle + deltaSpinAngle,
                                                           sectLidarAccumulator));
        }

        // get full spin Lidar buffer
        if (fullAccuStatus == DW_SUCCESS) {
            {
                ProfileCUDASection s(getProfilerCUDA(), "getSweep (Full)");
                CHECK_DW_ERROR(dwLidarAccumulator_getSweep(&fullLidarBuffer, fullLidarAccumulator));
            }

            {
                ProfileCUDASection s(getProfilerCUDA(), "fillImage (Full)");
                CHECK_DW_ERROR(dwLidarAccumulator_fillImage(fullLidarImage,
                                                            lidarImageType,
                                                            fullLidarAccumulator));
            }

            CHECK_DW_ERROR(dwRenderEngine_setBuffer(
                               renderBufferId[FULL_SPIN], DW_RENDER_ENGINE_PRIMITIVE_TYPE_POINTS_3D,
                               fullLidarBuffer.xyzi, sizeof(dwLidarPointXYZI), 0,
                               fullLidarBuffer.dataCount, renderEngine));

            validCount = fullLidarBuffer.validCount;
            renderText(fullLidarBuffer.dataCount, validCount, fullLidarBuffer.hostStartTime);
            CHECK_DW_ERROR(dwLidarAccumulator_returnSweep(fullLidarAccumulator));

            spinCount++;
        }

    }

    //#######################################################################################
    // Run the asynchronous pipeline
    // Read Lidar packet and do spin extraction in different threads
    //#######################################################################################
    void pipelineAsync()
    {
        dwStatus status;
        {
            ProfileCUDASection s(getProfilerCUDA(), "getSweep");
            status = dwLidarAccumulator_getSweep(&fullLidarBuffer, fullLidarAccumulator);
        }

        if (status == DW_NOT_AVAILABLE)
        {
            return;
        }
        else
        {
            CHECK_DW_ERROR(status);
        }

        {
            ProfileCUDASection s(getProfilerCUDA(), "fillImage");
            CHECK_DW_ERROR(dwLidarAccumulator_fillImage(fullLidarImage,
                                                        lidarImageType,
                                                        fullLidarAccumulator));
        }


        CHECK_DW_ERROR(dwRenderEngine_setBuffer(
                           renderBufferId[FULL_SPIN], DW_RENDER_ENGINE_PRIMITIVE_TYPE_POINTS_3D,
                           fullLidarBuffer.xyzi, sizeof(dwLidarPointXYZI), 0,
                           fullLidarBuffer.dataCount, renderEngine));

        validCount = fullLidarBuffer.validCount;
        renderText(fullLidarBuffer.dataCount, validCount, fullLidarBuffer.hostStartTime);

        CHECK_DW_ERROR(dwLidarAccumulator_returnSweep(fullLidarAccumulator));

        spinCount++;
    }

    // -----------------------------
    // initialize sensors
    // -----------------------------
    void initSensor()
    {
        dwSensorParams params{};

        std::string parameterString;
        std::string protocolString;

        bool validParameters = false;

        if (strcmp(getArgument("ip").c_str(), "") != 0) {

            if (strcmp(getArgument("port").c_str(), "") != 0) {

                if (strcmp(getArgument("device").c_str(), "") != 0) {

                    if (strcmp(getArgument("scan-frequency").c_str(), "") != 0) {
                        protocolString  = "lidar.socket";
                        parameterString = "ip=" + getArgument("ip");
                        parameterString += ",port=" + getArgument("port");
                        parameterString += ",device=" + getArgument("device");
                        parameterString += ",scan-frequency=" + getArgument("scan-frequency");

                        recordedLidar  = false;
                        validParameters = true;
                    }
                }
            }
        } else {
            if (strcmp(getArgument("file").c_str(), "") != 0) {
                protocolString  = "lidar.virtual";
                parameterString = "file=" + getArgument("file");

                // When reading from file, throttle the frame rate
                recordedLidar  = true;
                validParameters = true;
            }
        }

        if(!validParameters) {
            throw std::runtime_error("INVALID PARAMETERS");
        }

        params.protocol   = protocolString.c_str();
        params.parameters = parameterString.c_str();
        CHECK_DW_ERROR(dwSAL_createSensor(&lidarSensor, params, sal));
        dwSensorLidar_getProperties(&lidarProperties, lidarSensor);

        // we would like the application run as fast as the original video
        if (recordedLidar)
            setProcessRate(lidarProperties.spinFrequency);

        dwSensor_start(lidarSensor);
    }

    //#######################################################################################
    // Initialize Lidar Accumulators
    //#######################################################################################
    void initLidarAccumulators()
    {
        // Radial Distance
        minDistance = std::stof(getArgument("minDistance"));
        maxDistance = std::stof(getArgument("maxDistance"));
        minAngle    = std::stof(getArgument("minAngle"));
        maxAngle    = std::stof(getArgument("maxAngle"));

        if (getArgument("lidar-image-type") == "intensity")
            lidarImageType = DW_LIDAR_IMAGE_TYPE_INTENSITY_IMAGE;
        else if (getArgument("lidar-image-type") == "depth-xyz")
            lidarImageType = DW_LIDAR_IMAGE_TYPE_3D_DISTANCE_IMAGE;
        else
            throw std::runtime_error("unsupported lidar-image-type, must be one of "
                                     "'intensity' or 'depth-xyz'");

        // Window size for Lidar jittering smoothing
        uint32_t smoothWinSize = std::stol(getArgument("smooth-window-size"));

        if (std::find(supportedLidarDevices.begin(), supportedLidarDevices.end(),
                      std::string{lidarProperties.deviceString}) == supportedLidarDevices.end()) {
            throw std::runtime_error("unsupported lidar device type " +
                                     std::string(lidarProperties.deviceString));
        }

        CHECK_DW_ERROR(dwLidarAccumulator_initialize(&fullLidarAccumulator, smoothWinSize,
                                                     &lidarProperties, context));
        CHECK_DW_ERROR(dwLidarAccumulator_setDistanceSpan(minDistance, maxDistance, fullLidarAccumulator));


        // Init Sector Lidar Accumulator (every sector covers sectorAngle degree)
        CHECK_DW_ERROR(dwLidarAccumulator_initialize(&sectLidarAccumulator, smoothWinSize,
                                                     &lidarProperties, context));
        CHECK_DW_ERROR(dwLidarAccumulator_setAngleSpan(minAngle, maxAngle, sectLidarAccumulator));

        CHECK_DW_ERROR(dwLidarAccumulator_createImage(&fullLidarImage,
                                                      DW_LIDAR_IMAGE_TYPE_3D_DISTANCE_IMAGE,
                                                      fullLidarAccumulator));

        CHECK_DW_ERROR(dwLidarAccumulator_createImage(&sectLidarImage,
                                                      DW_LIDAR_IMAGE_TYPE_3D_DISTANCE_IMAGE,
                                                      sectLidarAccumulator));

    }

    //#######################################################################################
    // Initialize Renderer
    //#######################################################################################
    void initRenderer()
    {
        dwRenderEngineParams params;
        dwRenderEngine_initDefaultParams(&params, getWindowWidth(), getWindowHeight());

        // 1st tile (default) - Lidar spin points rendering
        {
            dwRenderEngine_initTileState(&params.defaultTile);
            params.defaultTile.lineWidth              = 2.f;
            params.defaultTile.font                   = DW_RENDER_ENGINE_FONT_VERDANA_16;

            params.defaultTile.layout.positionType    = DW_RENDER_ENGINE_TILE_POSITION_TYPE_TOP_LEFT;
            params.defaultTile.layout.positionLayout  = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            params.defaultTile.layout.sizeLayout      = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            params.defaultTile.layout.viewport.x      = 0;
            params.defaultTile.layout.viewport.y      = 0;
            params.defaultTile.layout.viewport.width  = getWindowWidth();
            params.defaultTile.layout.viewport.height = getWindowHeight() - 200;
        }

        CHECK_DW_ERROR(dwRenderEngine_initialize(&renderEngine, &params, context));

        // Depth image tiles
        {
            // full spin
            dwRenderEngineTileState tileParams = params.defaultTile;
            tileParams.projectionMatrix        = DW_IDENTITY_TRANSFORMATION;
            tileParams.modelViewMatrix         = DW_IDENTITY_TRANSFORMATION;
            tileParams.layout.positionType     = DW_RENDER_ENGINE_TILE_POSITION_TYPE_BOTTOM_LEFT;
            tileParams.layout.positionLayout   = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            tileParams.layout.sizeLayout       = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            tileParams.layout.viewport.x       = 0;
            tileParams.layout.viewport.y       = 0;
            tileParams.layout.viewport.width   = getWindowWidth();
            tileParams.layout.viewport.height  = 100;
            CHECK_DW_ERROR(dwRenderEngine_addTile(&tileId[FULL_SPIN], &tileParams, renderEngine));
        }

        {
            // sect spin
            dwRenderEngineTileState tileParams = params.defaultTile;
            tileParams.projectionMatrix        = DW_IDENTITY_TRANSFORMATION;
            tileParams.modelViewMatrix         = DW_IDENTITY_TRANSFORMATION;
            tileParams.layout.positionType     = DW_RENDER_ENGINE_TILE_POSITION_TYPE_BOTTOM_LEFT;
            tileParams.layout.positionLayout   = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            tileParams.layout.sizeLayout       = DW_RENDER_ENGINE_TILE_LAYOUT_TYPE_ABSOLUTE;
            tileParams.layout.viewport.x       = 0;
            tileParams.layout.viewport.y       = 100;
            tileParams.layout.viewport.width   = getWindowWidth();
            tileParams.layout.viewport.height  = 100;
            CHECK_DW_ERROR(dwRenderEngine_addTile(&tileId[SECT_SPIN], &tileParams, renderEngine));
        }

        CHECK_DW_ERROR(dwRenderEngine_createBuffer(
                &renderBufferId[FULL_SPIN], DW_RENDER_ENGINE_PRIMITIVE_TYPE_POINTS_3D,
                sizeof(dwLidarPointXYZI), 0, lidarProperties.pointsPerSpin, renderEngine));
        CHECK_DW_ERROR(dwRenderEngine_createBuffer(
                &renderBufferId[SECT_SPIN], DW_RENDER_ENGINE_PRIMITIVE_TYPE_POINTS_3D,
                sizeof(dwLidarPointXYZI), 0, lidarProperties.pointsPerSpin, renderEngine));
    }

    //#######################################################################################
    //  Render Depth Image
    //#######################################################################################
    void renderLidarImage(dwImageHandle_t &image)
    {
        if (!image2Gl) {
            return;
        }

        dwImageHandle_t imageGL = DW_NULL_HANDLE;

        CHECK_DW_ERROR(dwImageStreamer_producerSend(image, image2Gl));
        CHECK_DW_ERROR(dwImageStreamer_consumerReceive(&imageGL, 30000, image2Gl));

        if (imageGL) {
            dwImageGL* frameGL = nullptr;
            CHECK_DW_ERROR(dwImage_getGL(&frameGL, imageGL));

            dwVector2f range{};
            range.x = frameGL->prop.width;
            range.y = frameGL->prop.height;
            dwRenderEngine_setCoordinateRange2D(range, renderEngine);
            dwRenderEngine_renderImage2D(frameGL, {0.0f, 0.0f, range.x, range.y}, renderEngine);

            CHECK_DW_ERROR(dwImageStreamer_consumerReturn(&imageGL, image2Gl));
            CHECK_DW_ERROR(dwImageStreamer_producerReturn(nullptr, 30000, image2Gl));
        }
    }

    void renderText(uint32_t dataCount, uint32_t maxPoints, dwTime_t hostStartTime)
    {
        // Generate render text
        strBottom = "Point/Spin count   " + std::to_string(dataCount) + "/" + std::to_string(spinCount) + "\n" +
                    "Valid point count  " + std::to_string(maxPoints) + "\n" +
                    "Spin timestamp     " + std::to_string(hostStartTime) + "\n" +
                    "Frequency (Hz)     " + std::to_string(lidarProperties.spinFrequency);

        strTop = "Press ESC to exit\n"
                 "Press 0 or 1 to show Lidar intensity image or depth image\n"
                 "Press Left key or Right key to rotate counter-clock-wise or clock-wise";
    }
};


//#######################################################################################
// MAIN
//#######################################################################################
int main(int argc, const char *argv[])
{

    // init command line options
    ProgramArguments args(argc, argv,
    {
        ProgramArguments::Option_t("file", (DataPath::get() + "/samples/sensors/lidar/lidar_velodyne_64.bin").c_str(),
                                   "set it to recorded Lidar file if not using live Lidar sensor"),
        ProgramArguments::Option_t("mode", "sync",
                                   "mode=sync, it gets accumulated spin and visualizes the spin will be in the same thread, "
                                   "mode=async, it uses dedicated thread to accumulate the spin, the visualization runs in another thread"),
        ProgramArguments::Option_t("type", "cpu",
                                   "type=cpu, creates CPU lidar accumulator; type=gpu, creates GPU lidar accumulator"),
        ProgramArguments::Option_t("ip", "",
                                   "live Lidar sensor ip address, no need if using Lidar file"),
        ProgramArguments::Option_t("port", "",
                                   "live Lidar sensor port number, no need if using Lidar file"),
        ProgramArguments::Option_t("scan-frequency", "",
                                   "live Lidar sensor scan frequency, i.e. 5, 10, no need if using Lidar file"),
        ProgramArguments::Option_t("device", "",
                                   "live Lidar sensor type, i.e. device=VELO_HDL64E, no need if using Lidar file"),
        ProgramArguments::Option_t("minAngle", "30",
                                   "i.e. minAngle=50, Lidar accumulator will collect points whose azimuth > 50 degrees"),
        ProgramArguments::Option_t("maxAngle", "150",
                                   "i.e. maxAngle=100, Lidar accumulator will collect points whose azimuth <= 100 degrees"),
        ProgramArguments::Option_t("maxDistance", "200",
                                   "max distance (in meters) the accumulator covers, maxDistance > 131 will cover all distances"),
        ProgramArguments::Option_t("minDistance", "0",
                                   "min distance (in meters) the accumulator covers, "
                                   "i.e. min=10 will collect points at least 10 meters aways from Lidar"),
        ProgramArguments::Option_t("smooth-window-size", "4",
                                   "smoothing the Lidar horizontal jittering, smooth-window-size=1 or 2 or 4 or 8"),
        ProgramArguments::Option_t("lidar-image-type", "depth-xyz",
                                   "there are two options, lidar-image-type=depth-xyz or lidar-image-type=intensity")
    },
    "Lidar accumulator sample");

    // -------------------
    // initialize and start a window application
    LidarAccumulator app(args);

    app.initializeWindow("Lidar accumulator sample", 1280, 800, args.enabled("offscreen"));

    return app.run();
}

头文件就部分略过,从代码43行定义了一个LidarAccumulator类,从DriveworksSample类中继承,48行-95行定义了许多变量,含义可以从函数名看出来。

bool onInitialize()
initSensor()
initLidarAccumulators()
initRenderer()

分别进行了初始化。

DEMO中分别给了同步和异步两种方式。

   ./sample_lidar_accumulator --file=[path/to/recorded/lidar/data]
                               --mode=[sync|async]
                               --type=[cpu|gpu]
                               --ip=[ip_address]
                               --port=[port_number]
                               --scan-frequency=[integer]
                               --device=[VELO_HDL64E|VELO_HDL32E|VELO_VLP32C|VELO_VLP16HR|VELO_VLP16|QUAN_M81A]
                               --minAngle=[integer]
                               --maxAngle=[integer]
                               --maxDistance=[integer]
                               --minDistance=[integer]
                               --smooth-window-size=[1|2|4|8]
                               --lidar-image-type=[depth-xyz|intensity]


Where:

    --file=[path/to/recorded/lidar/data]
        Path to the recorded Lidar data.
        Default value: path/to/data/samples/sensors/lidar/lidar_velodyne_64.bin

    --mode=[sync|async]
        Allows to select a multi-thread implementation.
        When running in asynchronous mode the sample uses dedicated thread to accumulate the spin.
        Default value: sync

    --type=[cpu|gpu]
        Allows to select whether the accumulator is running on CPU or GPU.
        Default value: cpu

    --ip=[ip_address]
        Live Lidar sensor ip address. 
        Not applicable when replaying from file.
        Default value: none

    --port=[port_number]
        Live Lidar sensor port number.
        Not applicable when replaying from file.
        Default value: none

    --scan-frequency=[integer]
        Live Lidar sensor scan frequency.
        Not applicable when replaying from file.
        Default value: none

    --device=[VELO_HDL64E|VELO_HDL32E|VELO_VLP32C|VELO_VLP16HR|VELO_VLP16|QUAN_M81A]
        Live Lidar sensor type.
        Not applicable when replaying from file.
        Default value: none

    --minAngle=[integer]
        Lidar accumulator will collect points whose azimuth is greather than minAngle degrees.
        Default value: 50

    --maxAngle=[integer]
        Lidar accumulator will collect points whose azimuth less or equal than maxAngle degrees.
        Default value: 100

    --maxDistance=[integer]
        Maximum distance in meters covered by the accumulator.
        Whenever maxDistance is set to 131 or higher, all distances are covered.
        Default value: 200

    --minDistance=[integer]
        Minumum distance in meters covered by the accumulator.
        E.g. a minimum distance of 10m meters will collect points that are at least
        10 meters away from the Lidar.
        Default value: 0

    --smooth-window-size=[1|2|4|8]
        smooth-window-size allows the user to smooth the Lidar points jittering in horizontal 
        direction due to the spinning noise. For example, for Velodyne HDL64E each Lidar beam 
        has 3480 points in dual mode. With smooth-window-size=4, Lidar Accumulator chooses one 
        single point out of every 4 adjacent Lidar points based on closest 3D distance from the 
        Lidar sensor.
        Default value: 4

    --lidar-image-type=[depth-xyz|intensity]
        Specifies the type of cylindrical image.
        Default value: depth-xyz

Following interactions with the sample are available at runtime:

- Mouse left button: rotate the point cloud
- Mouse wheel: zoom in or out
- Key 0: show the intensity image
- Key 1: show the depth image
- Left Key: rotate the sector spin in counter-clock direction
- Right Key: rotate the sector spin in clock direction

@section dwx_lidar_accumulator_sample_examples Examples

#### Run with live Lidar sensor

    ./sample_lidar_accumulator --ip=[Lidar IP address] --port=[Lidar port] --device=[type of device] --scan-frequency=[valid frequency]
        --mode=[sync or async]
        --maxDistance[max distance in meters to select the Lidar points, maxDistance > 131 will cover all distances]
        --minDistance[min distance in meters to select the Lidar points]
        --minAngle[min angle in degrees to select the Lidar points]
        --maxAngle[max angle in degrees to select the Lidar points]
        --smooth-window-size[1, 2, 4, 8]
        --lidar-image-type[depth-xyz or intensity]

- The Lidar must be connected to the network.
- Scan frequency is usually preset using the Lidar vendor tools.

#### Run with recorded Lidar binary file

    ./sample_lidar_accumulator --file=[Lidar binary file] --mode=[sync or async]
        --maxDistance[max distance in meters to select the Lidar points, maxDistance > 131 will cover all distances]
        --minDistance[min distance in meters to select the Lidar points]
        --minAngle[min angle in degrees to select the Lidar points]
        --maxAngle[max angle in degrees to select the Lidar points]
        --smooth-window-size[1, 2, 4, 8]
        --lidar-image-type[depth-xyz or intensity]

- The Lidar file can be obtained with the provided recording tools.
- If no arguments are passed, a default Lidar file is loaded and default parameters are used.

@section dwx_lidar_accumulator_sample_output Output

The sample opens a window to display a full sweep of 3D point cloud, a rolling sector sweep of the 3D point cloud and a projected cylindrical image on the bottom.

![Lidar Accumulator Sample](sample_lidar_accumulator.png)

@section dwx_lidar_accumulator_sample_more Additional Information

For more details see @ref lidaraccumulator_mainsection .
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值