从0到1搭建一套属于你自己的高精度实时结构光3D相机(4):投影仪控制(C/C++)

1. 写在前面

在前面的博客中,介绍了如何通过 C/C++ 控制我们的2D相机。在这篇博客中,博主将教给大家如何通过 C/C++ 控制我们的投影仪。完成本篇博客的学习内容后,你将收获投影仪的SDK 使用经验。

本系列博客的完整项目代码皆位于博主的Github项目SLMaster👈

https://github.com/Practice3DVision/SLMaster

动动你的小指头给个Star⭐并follow博主吧!你的支持是博主不懈的动力!

2. 投影仪C/C++控制

在前一篇博客中,博主介绍了如何去设计相机的业务逻辑,其中提到了通过接口继承、简单工厂模式延迟具体实现,从而实现高内聚低耦合的效果。投影仪的业务逻辑与之相似,我们直接给出UML图:

投影仪UML图
是不是感觉一摸一样!

接下来我们就要开始实现投影仪控制的 C/C++ 代码了。

首先当然是找到德州仪器官方给到我们的SDK了。

对于34xx系列的控制器,我们使用DLPC-API👈,对于DLP 4500DLP 6500等使用DLP-ALC-LIGHTCRAFTER-SDK👈。博主将使用DLPC-API实现控制进行介绍,DLP-ALC-LIGHTCRAFTER-SDK与之同理(主要是博主懒,没写这个…)。

博主采用的是将SDK源文件继承到项目内的做法(谁让它文件数少呢,就是任性)。总的来说,你需要拷贝common.hppcypress_i2c.hdlpc_common_private.hdlpc_common.hdlpc34xx_dual.hdlpc34xx.hdlpc347x_internal_patterns.hdlpc654x.h以及对应的源文件到你的工程文件夹下,此外,你还需要将cyusbserial第三方库加入到你的工程项目下(DLPC-API文件夹内有啦)。

让我们开始敲起键盘吧!

老样子,我们先做一个类型定义头文件 typeDef.h ,用于静态库/动态库的宏定义等。

//typeDef.h

#ifndef IN
#define IN //输入
#endif

#ifndef OUT
#define OUT //输出
#endif

# ifdef BUILD_SHARED_LIBS
#   ifdef _WIN32
#       ifdef DLL_EXPORTS
#           define DEVICE_API _declspec(dllexport)
#       else
#           define DEVICE_API _declspec(dllimport)
#       endif
#   else
#       define DEVICE_API
#   endif
# else
#   define DEVICE_API
# endif

然后,我们定义一个common.hpp文件,放入34xx系列投影仪控制类都会用到的方法。

//common.hpp

#ifndef __PROJECTOR_COMMON_H_
#define __PROJECTOR_COMMON_H_

#include "typeDef.h"

#include "cypress_i2c.h"
#include "dlpc34xx.h"
#include "dlpc34xx_dual.h"
#include "math.h"
#include "stdio.h"
#include "time.h"

#define FLASH_WRITE_BLOCK_SIZE 1024
#define FLASH_READ_BLOCK_SIZE 256

#define MAX_WRITE_CMD_PAYLOAD (FLASH_WRITE_BLOCK_SIZE + 8)
#define MAX_READ_CMD_PAYLOAD (FLASH_READ_BLOCK_SIZE + 8)

static uint8_t s_WriteBuffer[MAX_WRITE_CMD_PAYLOAD];
static uint8_t s_ReadBuffer[MAX_READ_CMD_PAYLOAD];

static bool s_StartProgramming;
static uint8_t s_FlashProgramBuffer[FLASH_WRITE_BLOCK_SIZE];
static uint16_t s_FlashProgramBufferPtr;

/**
 * @brief 通过Cypress USB-Serial写入数据
 *
 * @param writeDataLength 写入数据长度
 * @param writeData 写入数据
 * @param protocolData 命令符
 * @return int32_t 成功与否
 */
static uint32_t writeI2C(IN uint16_t writeDataLength, IN uint8_t *writeData,
                         IN DLPC_COMMON_CommandProtocolData_s *protocolData) {
    bool Status = true;
    Status = CYPRESS_I2C_WriteI2C(writeDataLength, writeData);
    if (Status != true) {
        printf("Write I2C Error!!! \n");
        return FAIL;
    }

    return SUCCESS;
}
/**
 * @brief 通过Cypress USB-Serial读取数据
 *
 * @param writeDataLength 写入数据长度
 * @param writeData 写入数据
 * @param readDataLength 读取数据长度
 * @param readData 读取到的数据
 * @param protocolData 命令符
 * @return int32_t 成功与否
 */
static uint32_t readI2C(IN uint16_t writeDataLength, IN uint8_t *writeData,
                        IN uint16_t readDataLength, IN uint8_t *readData,
                        IN DLPC_COMMON_CommandProtocolData_s *protocolData) {
    bool Status = 0;
    Status = CYPRESS_I2C_WriteI2C(writeDataLength, writeData);
    if (Status != true) {
        printf("Write I2C Error!!! \n");
        return FAIL;
    }

    Status = CYPRESS_I2C_ReadI2C(readDataLength, readData);
    if (Status != true) {
        printf("Read I2C Error!!! \n");
        return FAIL;
    }

    return SUCCESS;
}
/**
 * @brief 等待
 *
 * @param seconds 等待的时间(s)
 */
static void waitForSeconds(IN uint32_t seconds) {
    uint32_t retTime = (uint32_t)(time(0)) + seconds;
    while (time(0) < retTime);
}

/**
 * @brief 拷贝数据至flash内存
 *
 * @param length 长度
 * @param pData 数据
 */
static void copyDataToFlashProgramBuffer(IN uint8_t *length,
                                         IN uint8_t **pData) {
    while ((*length >= 1) &&
           (s_FlashProgramBufferPtr < sizeof(s_FlashProgramBuffer))) {
        s_FlashProgramBuffer[s_FlashProgramBufferPtr] = **pData;
        s_FlashProgramBufferPtr++;
        (*pData)++;
        (*length)--;
    }
}

/**
 * @brief 烧录
 *
 * @param length 数据长度
 */
static void programDualFlashWithDataInBuffer(IN uint16_t length) {
    s_FlashProgramBufferPtr = 0;

    if (s_StartProgramming) {
        s_StartProgramming = false;
        DLPC34XX_DUAL_WriteFlashStart(length, s_FlashProgramBuffer);
    } else {
        DLPC34XX_DUAL_WriteFlashContinue(length, s_FlashProgramBuffer);
    }
}

/**
 * @brief 烧录
 *
 * @param length 数据长度
 */
static void programFlashWithDataInBuffer(IN uint16_t length) {
    s_FlashProgramBufferPtr = 0;

    if (s_StartProgramming) {
        s_StartProgramming = false;
        DLPC34XX_WriteFlashStart(length, s_FlashProgramBuffer);
    } else {
        DLPC34XX_WriteFlashContinue(length, s_FlashProgramBuffer);
    }
}

/**
 * @brief 打包数据并烧录
 *
 * @param length 数据长度
 * @param pData 数据
 */
static void bufferDualPatternDataAndProgramToFlash(IN uint8_t length,
                                               IN uint8_t *pData) {
    copyDataToFlashProgramBuffer(&length, &pData);

    if (s_FlashProgramBufferPtr >= sizeof(s_FlashProgramBuffer)) {
        programDualFlashWithDataInBuffer((uint16_t)sizeof(s_FlashProgramBuffer));
    }

    copyDataToFlashProgramBuffer(&length, &pData);
}

/**
 * @brief 打包数据并烧录
 *
 * @param length 数据长度
 * @param pData 数据
 */
static void bufferPatternDataAndProgramToFlash(IN uint8_t length,
                                               IN uint8_t *pData) {
    copyDataToFlashProgramBuffer(&length, &pData);

    if (s_FlashProgramBufferPtr >= sizeof(s_FlashProgramBuffer)) {
        programFlashWithDataInBuffer((uint16_t)sizeof(s_FlashProgramBuffer));
    }

    copyDataToFlashProgramBuffer(&length, &pData);
}

#endif // !__PROJECTOR_COMMON_H_

然后,实现我们的纯虚基类Projector,它用于定义我们投影仪的业务逻辑(接口方法)。此外,博主还使用了OpenCVMat接口,毕竟太常用了!

//projector.h

#ifndef __PROJECTOR_H_
#define __PROJECTOR_H_

#include "typeDef.h"

#include <opencv2/opencv.hpp>

namespace device {
/** @brief 投影仪库 */
namespace projector {
/** @brief 投影仪LED灯 */
enum Illumination { Red = 0, Grren, Blue, RGB };

/** @brief 投影图案集合 */
struct DEVICE_API PatternOrderSet {
    std::vector<cv::Mat> imgs_; //需要制作集合的图片
    // int __patternSetIndex;        //集合索引
    int patternArrayCounts_;    //图片数组数量
    Illumination illumination_; // LED控制
    bool invertPatterns_;       //反转图片
    bool isVertical_;           //是否水平图片
    bool isOneBit_;             //是否为一位深度
    int exposureTime_;          //曝光时间(us)
    int preExposureTime_;       //曝光前时间(us)
    int postExposureTime_;      //曝光后时间(us)
};

/** @brief 相机信息 **/
struct DEVICE_API ProjectorInfo {
    std::string dlpEvmType_; // DLP评估模块
    int width_;              //幅面宽度
    int height_;             //幅面高度
    bool isFind_;            //是否找到
};

/** @brief 投影仪控制类 */
class DEVICE_API Projector {
  public:
    virtual ~Projector() {}
    /**
     * @brief 获取投影仪信息
     *
     * @return ProjectorInfo 投影仪相关信息
     */
    virtual ProjectorInfo getInfo() = 0;
    /**
     * @brief 连接
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool connect() = 0;
    /**
     * @brief 断开连接
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool disConnect() = 0;
    /**
     * @brief 断开连接
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool isConnect() = 0;
    /**
     * @brief 从图案集制作投影序列
     *
     * @param table 投影图案集
     */
    virtual bool
    populatePatternTableData(IN std::vector<PatternOrderSet> table) = 0;
    /**
     * @brief 投影
     *
     * @param isContinue 是否连续投影
     * @return true 成功
     * @return false 失败
     */
    virtual bool project(IN const bool isContinue) = 0;
    /**
     * @brief 暂停
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool pause() = 0;
    /**
     * @brief 停止
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool stop() = 0;
    /**
     * @brief 恢复投影
     *
     * @return true 成功
     * @return false 失败
     */
    virtual bool resume() = 0;
    /**
     * @brief 投影下一帧
     * @warning 仅在步进模式下使用
     *
     * @return true
     * @return false
     */
    virtual bool step() = 0;
    /**
     * @brief 获取当前LED三色灯电流值
     *
     * @param r 红色电流值
     * @param g 绿色电流值
     * @param b 蓝色电流值
     * @return true 成功
     * @return false 失败
     */
    virtual bool getLEDCurrent(OUT double &r, OUT double &g, OUT double &b) = 0;
    /**
     * @brief 设置当前LED三色灯电流值
     *
     * @param r 红色电流值
     * @param g 绿色电流值
     * @param b 蓝色电流值
     * @return true 成功
     * @return false 失败
     */
    virtual bool setLEDCurrent(IN const double r, IN const double g,
                               IN const double b) = 0;
    /**
     * @brief 获取当前闪存图片数量
     *
     * @return int 图片数量
     */
    virtual int getFlashImgsNum() = 0;
  private:
};
} // namespace projector
} // namespace device

#endif //!__PROJECTOR_H_

随后,我们实现单控制器下的34xx系列投影仪控制类projectorDlpc34xx.h

//projectorDlpc34xx.h

#ifndef __PROJECTOR_DLPC_34xx_H_
#define __PROJECTOR_DLPC_34xx_H_

#include "projector.h"

#include "dlpc347x_internal_patterns.h"
#include "dlpc_common.h"

#include <time.h>

/** @brief 结构光相机库 */
namespace device {
/** @brief 投影仪库 */
namespace projector {
/** @brief DLPC34xx系列投影仪 */
class DEVICE_API ProjectorDlpc34xx : public Projector {
  public:
    ProjectorDlpc34xx();
    ~ProjectorDlpc34xx();
    /**
     * @brief 获取投影仪信息
     *
     * @return ProjectorInfo 投影仪相关信息
     */
    ProjectorInfo getInfo() override;
    /**
     * @brief 连接
     *
     * @return true 成功
     * @return false 失败
     */
    bool connect() override;
    /**
     * @brief 断开连接
     *
     * @return true 成功
     * @return false 失败
     */
    bool disConnect() override;
    /**
     * @brief 断开连接
     *
     * @return true 成功
     * @return false 失败
     */
    bool isConnect() override;
    /**
     * @brief 从图案集制作投影序列
     *
     * @param table 投影图案集
     */
    bool
    populatePatternTableData(IN std::vector<PatternOrderSet> table) override;
    /**
     * @brief 投影
     *
     * @param isContinue 是否连续投影
     * @return true 成功
     * @return false 失败
     */
    bool project(IN const bool isContinue) override;
    /**
     * @brief 停止
     *
     * @return true 成功
     * @return false 失败
     */
    bool stop() override;
    /**
     * @brief 恢复投影
     *
     * @return true 成功
     * @return false 失败
     */
    bool resume() override;
    /**
     * @brief 暂停
     *
     * @return true 成功
     * @return false 失败
     */
    bool pause() override;
    /**
     * @brief 投影下一帧
     * @warning 仅在步进模式下使用
     *
     * @return true
     * @return false
     */
    bool step() override;
    /**
     * @brief 获取当前LED三色灯电流值
     *
     * @param r 红色电流值
     * @param g 绿色电流值
     * @param b 蓝色电流值
     * @return true 成功
     * @return false 失败
     */
    bool getLEDCurrent(OUT double &r, OUT double &g, OUT double &b) override;
    /**
     * @brief 设置当前LED三色灯电流值
     *
     * @param r 红色电流值
     * @param g 绿色电流值
     * @param b 蓝色电流值
     * @return true 成功
     * @return false 失败
     */
    bool setLEDCurrent(IN const double r, IN const double g,
                       IN const double b) override;
    /**
     * @brief 获取当前闪存图片数量
     *
     * @return int 图片数量
     */
    int getFlashImgsNum() override;
  private:
    /**
     * @brief 初始化Cypress USB-Serial和DLPC控制器
     *
     * @return bool 成功初始化
     */
    bool initConnectionAndCommandLayer();
    /**
     * @brief 从flash加载图案序列
     *
     */
    void loadPatternOrderTableEntryFromFlash();
    //是否已成功初始化
    bool isInitial_;
    //投影仪幅面列数
    uint16_t cols_;
    //投影仪幅面行数
    uint16_t rows_;
    //图案数量
    int numOfPatterns_;
    //图案集合数量
    int numOfPatternSets_;
};
} // namespace projector
} // namespace sl

#endif // !__PROJECTOR_DLPC_34xx_H_
//projectorDlpc34xx.cpp

#include "projectorDlpc34xx.h"

#include "common.hpp"

#include "CyUSBSerial.h"

namespace device {
namespace projector {

void ProjectorDlpc34xx::loadPatternOrderTableEntryFromFlash() {
    DLPC34XX_PatternOrderTableEntry_s PatternOrderTableEntry;

    DLPC34XX_WritePatternOrderTableEntry(DLPC34XX_WC_RELOAD_FROM_FLASH,
                                         &PatternOrderTableEntry);
}

bool ProjectorDlpc34xx::initConnectionAndCommandLayer() {
    DLPC_COMMON_InitCommandLibrary(s_WriteBuffer, sizeof(s_WriteBuffer),
                                   s_ReadBuffer, sizeof(s_ReadBuffer), writeI2C,
                                   readI2C);

    isInitial_ = CYPRESS_I2C_ConnectToCyI2C();

    return isInitial_;
}

ProjectorDlpc34xx::ProjectorDlpc34xx() : isInitial_(false) {
    cols_ = DLP3010_WIDTH;
    rows_ = DLP3010_HEIGHT;
}

bool ProjectorDlpc34xx::connect() {
    bool isInitSucess = initConnectionAndCommandLayer();
    if (!isInitSucess) {
        printf("init DLPC-USB connection error! \n");
        return false;
    }

    if (!CYPRESS_I2C_RequestI2CBusAccess()) {
        printf("Error request I2C bus access! \n");
        return false;
    }

    loadPatternOrderTableEntryFromFlash();

    //DLPC34XX_WriteInputImageSize(cols_, rows_);
    //DLPC34XX_WriteImageCrop(0, 0, cols_, rows_);
    //DLPC34XX_WriteDisplaySize(0, 0, cols_, rows_);

    DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_STOP, 0);
    DLPC34XX_WriteTriggerOutConfiguration(
        DLPC34XX_TT_TRIGGER1, DLPC34XX_TE_ENABLE, DLPC34XX_TI_NOT_INVERTED, 0);
    DLPC34XX_WriteTriggerOutConfiguration(
        DLPC34XX_TT_TRIGGER2, DLPC34XX_TE_ENABLE, DLPC34XX_TI_NOT_INVERTED, 0);
    DLPC34XX_WriteTriggerInConfiguration(DLPC34XX_TE_DISABLE,
                                         DLPC34XX_TP_ACTIVE_HI);
    DLPC34XX_WritePatternReadyConfiguration(DLPC34XX_TE_ENABLE,
                                            DLPC34XX_TP_ACTIVE_HI);
    DLPC34XX_WriteOperatingModeSelect(DLPC34XX_OM_SENS_INTERNAL_PATTERN);

    return true;
}

bool ProjectorDlpc34xx::disConnect() {
    if(!isInitial_) {
        return false;
    }

    uint8_t numDevices;
    CyGetListofDevices(&numDevices);
    for (size_t i = 0; i < numDevices; ++i) {
        CY_DEVICE_INFO deviceInfo;
        CyGetDeviceInfo(i, &deviceInfo);
        CY_HANDLE handle;
        unsigned char sig[6];
        if(deviceInfo.deviceType[i] == CY_DEVICE_TYPE::CY_TYPE_I2C && deviceInfo.deviceClass[i] == CY_CLASS_VENDOR) {
            if (CY_SUCCESS == CyOpen(i, 0, &handle)) {
                CyClose(handle);
                break;
            }
        }
    }
    
    return true;
}

bool ProjectorDlpc34xx::isConnect() {
    if(!isInitial_) {
        return false;
    }

    DLPC34XX_ShortStatus_s shortStatus;
    DLPC34XX_ReadShortStatus(&shortStatus);
    return shortStatus.SystemError == DLPC34XX_E_NO_ERROR;
}

bool ProjectorDlpc34xx::populatePatternTableData(
    std::vector<PatternOrderSet> table) {
    if (!isConnect()) {
        return false;
    }

    numOfPatternSets_ = table.size();
    numOfPatterns_ = 0;
    for (size_t i = 0; i < table.size(); ++i) {
        numOfPatterns_ += table[i].imgs_.size();
    }

    DLPC34XX_INT_PAT_PatternData_s *patterns =
        new DLPC34XX_INT_PAT_PatternData_s[numOfPatterns_];
    DLPC34XX_INT_PAT_PatternSet_s *patternSets =
        new DLPC34XX_INT_PAT_PatternSet_s[numOfPatternSets_];
    DLPC34XX_INT_PAT_PatternOrderTableEntry_s *patternOrderTableEntries =
        new DLPC34XX_INT_PAT_PatternOrderTableEntry_s[numOfPatternSets_];

    int indexOfPattern = 0;
    for (size_t i = 0; i < table.size(); ++i) {
        patternSets[i].BitDepth = table[i].isOneBit_ == true
                                      ? DLPC34XX_INT_PAT_BITDEPTH_ONE
                                      : DLPC34XX_INT_PAT_BITDEPTH_EIGHT;
        patternSets[i].Direction = table[i].isVertical_ == true
                                       ? DLPC34XX_INT_PAT_DIRECTION_VERTICAL
                                       : DLPC34XX_INT_PAT_DIRECTION_HORIZONTAL;
        patternSets[i].PatternArray = &patterns[indexOfPattern];
        patternSets[i].PatternCount = table[i].imgs_.size();

        for (size_t j = 0; j < table[i].imgs_.size(); ++j) {
            patterns[indexOfPattern].PixelArrayCount =
                table[i].patternArrayCounts_;

            table[i].imgs_[j] = table[i].isVertical_ ? table[i].imgs_[j] : table[i].imgs_[j].t();
            patterns[indexOfPattern].PixelArray = table[i].imgs_[j].data;
            ++indexOfPattern;
        }

        patternOrderTableEntries[i].PatternSetIndex = i;
        patternOrderTableEntries[i].NumDisplayPatterns =
            patternSets[i].PatternCount;
        patternOrderTableEntries[i].IlluminationSelect =
            (table[i].illumination_ == Red ? DLPC34XX_INT_PAT_ILLUMINATION_RED
             : table[i].illumination_ == Grren
                 ? DLPC34XX_INT_PAT_ILLUMINATION_GREEN
                 : table[i].illumination_ == Blue ? DLPC34XX_INT_PAT_ILLUMINATION_BLUE : DLPC34XX_INT_PAT_ILLUMINATION_RGB);
        patternOrderTableEntries[i].InvertPatterns = false;
        patternOrderTableEntries[i].IlluminationTimeInMicroseconds =
            table[i].exposureTime_;
        patternOrderTableEntries[i].PreIlluminationDarkTimeInMicroseconds =
            table[i].preExposureTime_;
        patternOrderTableEntries[i].PostIlluminationDarkTimeInMicroseconds =
            table[i].postExposureTime_;
    }

    DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_STOP, 0);

    s_StartProgramming = true;
    s_FlashProgramBufferPtr = 0;

    DLPC34XX_WriteFlashDataTypeSelect(
        DLPC34XX_FDTS_ENTIRE_SENS_PATTERN_DATA);
    DLPC34XX_WriteFlashErase();
    DLPC34XX_ShortStatus_s ShortStatus;
    do {
        DLPC34XX_ReadShortStatus(&ShortStatus);
    } while (ShortStatus.FlashEraseComplete == DLPC34XX_FE_NOT_COMPLETE);

    DLPC34XX_WriteFlashDataLength(sizeof(s_FlashProgramBuffer));

    DLPC34XX_INT_PAT_GeneratePatternDataBlock(
        DLPC34XX_INT_PAT_DMD_DLP4710, numOfPatternSets_, patternSets,
        numOfPatternSets_, patternOrderTableEntries,
        bufferPatternDataAndProgramToFlash, false, false);
    if (s_FlashProgramBufferPtr > 0) {
        DLPC34XX_WriteFlashDataLength(s_FlashProgramBufferPtr);

        programFlashWithDataInBuffer(s_FlashProgramBufferPtr);
    }

    loadPatternOrderTableEntryFromFlash();

    s_StartProgramming = false;

    delete[] patternOrderTableEntries;
    delete[] patternSets;
    delete[] patterns;

    return true;
}

bool ProjectorDlpc34xx::project(const bool isContinue) {
    if(!isInitial_) {
        return false;
    }

    if (isContinue) {
        DLPC34XX_WriteOperatingModeSelect(DLPC34XX_OM_SENS_INTERNAL_PATTERN);
        return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_START, 0xFF) ==
               SUCCESS;
    } else {
        DLPC34XX_WriteOperatingModeSelect(DLPC34XX_OM_SENS_INTERNAL_PATTERN);
        return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_START, 0x0) ==
               SUCCESS;
    }

    return true;
}

bool ProjectorDlpc34xx::stop() {
    if(!isInitial_) {
        return false;
    }

    return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_STOP, 0) == SUCCESS;
}

bool ProjectorDlpc34xx::pause() {
    if(!isInitial_) {
        return false;
    }

    return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_PAUSE, 0xff) ==
           SUCCESS;
}

bool ProjectorDlpc34xx::resume() {
    if(!isInitial_) {
        return false;
    }

    return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_RESUME, 0xff) ==
           SUCCESS;
}

bool ProjectorDlpc34xx::step() {
    if(!isInitial_) {
        return false;
    }

    return DLPC34XX_WriteInternalPatternControl(DLPC34XX_PC_STEP, 0xff) ==
           SUCCESS;
}

bool ProjectorDlpc34xx::getLEDCurrent(OUT double &r, OUT double &g,
                                      OUT double &b) {
    if(!isInitial_) {
        return false;
    }

    uint16_t red, green, blue, maxRed, maxGreen, maxBlue;
    auto isSucess = DLPC34XX_ReadRgbLedCurrent(&red, &green, &blue);
    isSucess = DLPC34XX_ReadRgbLedMaxCurrent(&maxRed, &maxGreen, &maxBlue);
    r = (double)red / maxRed;
    g = (double)red / maxRed;
    b = (double)red / maxRed;

    return isSucess == SUCCESS;
}

bool ProjectorDlpc34xx::setLEDCurrent(IN const double r, IN const double g,
                                      IN const double b) {
    if(!isInitial_) {
        return false;
    }

    uint16_t maxRed, maxGreen, maxBlue;
    bool isSucess = DLPC34XX_WriteRgbLedEnable(true, true, true);
    isSucess = DLPC34XX_ReadRgbLedMaxCurrent(&maxRed, &maxGreen, &maxBlue);
    isSucess =
        DLPC34XX_WriteRgbLedCurrent(maxRed * r, maxGreen * g, maxBlue * b);

    return isSucess == SUCCESS;
}

int ProjectorDlpc34xx::getFlashImgsNum() {
    if(!isInitial_) {
        return false;
    }

    DLPC34XX_InternalPatternStatus_s status;
    DLPC34XX_ReadInternalPatternStatus(&status);

    return status.NumPatDisplayedFromPatSet;
}

ProjectorDlpc34xx::~ProjectorDlpc34xx() {
}

ProjectorInfo ProjectorDlpc34xx::getInfo() {
    ProjectorInfo projectorInfo;
    projectorInfo.dlpEvmType_ = "DLP4710";
    projectorInfo.width_ = cols_;
    projectorInfo.height_ = rows_;
    projectorInfo.isFind_ = false;

    uint8_t numDevices;
    CyGetListofDevices(&numDevices);
    for (size_t i = 0; i < numDevices; ++i) {
        CY_DEVICE_INFO deviceInfo;
        CyGetDeviceInfo(i, &deviceInfo);
        CY_HANDLE handle;
        unsigned char sig[6];
        if(deviceInfo.deviceType[i] == CY_DEVICE_TYPE::CY_TYPE_I2C && deviceInfo.deviceClass[i] == CY_CLASS_VENDOR) {
            projectorInfo.isFind_ = true;
            break;
        }
    }

    return projectorInfo;
}

} // namespace projector
} // namespace sl

如此一来,我们就实现对单控制器下的投影仪 C/C++ 控制了,对于双控制器,与之类似,博主就不大费周章再复制一遍代码了,可以见博主的SLMaster项目👈

注意!!!
双控制器SDK存在bug,投影图案与烧录图案不对。博主曾在德州仪器论坛发帖咨询,然无果后自行调试和寻找解决方案,最后发现只需将双控制器中的东西翻转和长轴短轴翻转皆修改一下即可,详情请对比博主代码与官方代码。

最后,为了方便调用并进一步延后实现,我们定义简单工厂类ProjectorFactory

//projectorFactory.h

#ifndef __PROJECTORY_FACTORY_H_
#define __PROJECTORY_FACTORY_H_

#include <string>
#include <unordered_map>

#include "projector.h"
#include "projectorDlpc34xx.h"
#include "projectorDlpc34xxDual.h"

#include "typeDef.h"

/** @brief 结构光库 **/
namespace device {
/** @brief 投影仪库 **/
namespace projector {
/** @brief 投影仪工厂 **/
class DEVICE_API ProjectorFactory {
  public:
    ProjectorFactory() { };

    Projector *getProjector(const std::string dlpEvm) {
        Projector *projector = nullptr;

        if (projectoies_.count(dlpEvm)) {
            return projectoies_[dlpEvm];
        } else {
            if ("DLP4710" == dlpEvm) {
                projector = new ProjectorDlpc34xxDual();
                projectoies_[dlpEvm] = projector;
            }
            
            else if ("DLP3010" == dlpEvm) {
                projector = new ProjectorDlpc34xx();
                projectoies_[dlpEvm] = projector;
            }
            //TODO@Evans Liu: 增加DLP6500支持
        }

        return projector;
    }
  private:
    std::unordered_map<std::string, Projector *> projectoies_;
}; // class ProjectorFactory
} // namespace projector
} // namespace device

#endif //__PROJECTORY_FACTORY_H_

大功告成了! 老套路,我们写个单元测试来测试测试我们的代码。

#include <gtest/gtest.h>

#include <projectorFactory.h>

const std::string testProjector4710 = "DLP4710";
const std::string testProjector3010 = "DLP3010";
const std::string testData4710 = "../../test/data/4_4710";
const std::string testData3010 = "../../test/data/4_3010";

TEST(Projector, init) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    ASSERT_NE(projectorDlpcApi, nullptr);
}

TEST(Projector, getInfo) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    auto info = projectorDlpcApi->getInfo();
    ASSERT_EQ(info.isFind_, true);
}

TEST(Project, connect) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    ASSERT_EQ(isSucess, true);
    isSucess = projectorDlpcApi->disConnect();
}

TEST(Project, isConnect) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->isConnect();
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->disConnect();
}

TEST(Project, disconnect) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    ASSERT_EQ(projectorDlpcApi->disConnect(), true);
}

TEST(Project, onceProject) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(false);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->stop();
    projectorDlpcApi->disConnect();
}

TEST(Project, continueProject) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(true);
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->stop();
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

TEST(Project, pause) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(true);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->pause();
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->stop();
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

TEST(Project, resume) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(true);
    isSucess = projectorDlpcApi->pause();
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
    isSucess = projectorDlpcApi->resume();
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->stop();
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

TEST(Project, stop) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(true);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->stop();
    ASSERT_EQ(isSucess, true);
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

TEST(Projector, populatePatternTableData) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();

    ASSERT_EQ(isSucess, true);

    std::vector<device::projector::PatternOrderSet> patternSets(2);
    patternSets[0].exposureTime_ = 4000;
    patternSets[0].preExposureTime_ = 3000;
    patternSets[0].postExposureTime_ = 3000;
    patternSets[0].illumination_ = device::projector::Blue;
    patternSets[0].invertPatterns_ = false;
    patternSets[0].isVertical_ = true;
    patternSets[0].isOneBit_ = false;
    patternSets[0].patternArrayCounts_ = 1920;
    patternSets[1].exposureTime_ = 4000;
    patternSets[1].preExposureTime_ = 3000;
    patternSets[1].postExposureTime_ = 3000;
    patternSets[1].illumination_ = device::projector::Blue;
    patternSets[1].invertPatterns_ = false;
    patternSets[1].isVertical_ = true;
    patternSets[1].isOneBit_ = false;
    patternSets[1].patternArrayCounts_ = 1920;

    std::vector<cv::String> imgsPaths;
    cv::glob(testData4710, imgsPaths);
    std::vector<cv::Mat> imgFirstSet;
    std::vector<cv::Mat> imgSecondSet;
    for (size_t i = 0; i < imgsPaths.size() / 2; ++i) {
        imgFirstSet.push_back(cv::imread(testData4710 + "/" + std::to_string(i) + ".bmp", 0));
        imgSecondSet.push_back(cv::imread(testData4710 + "/" + std::to_string(i + 5) + ".bmp", 0));
    }
    patternSets[0].imgs_ = imgFirstSet;
    patternSets[1].imgs_ = imgSecondSet;

    ASSERT_EQ(patternSets[0].imgs_.empty(), false);
    ASSERT_EQ(patternSets[1].imgs_.empty(), false);

    isSucess = projectorDlpcApi->populatePatternTableData(patternSets);
    ASSERT_EQ(isSucess, true);
    projectorDlpcApi->project(true);
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    projectorDlpcApi->stop();
    projectorDlpcApi->disConnect();
}

TEST(Project, step) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    isSucess = projectorDlpcApi->project(true);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->step();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->step();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->step();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->step();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    isSucess = projectorDlpcApi->stop();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    ASSERT_EQ(isSucess, true);
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

TEST(Project, getSetLEDCurrent) {
    auto projectorFactory = device::projector::ProjectorFactory();
    auto projectorDlpcApi = projectorFactory.getProjector(testProjector4710);
    bool isSucess = projectorDlpcApi->connect();
    double red, green, blue;
    isSucess = projectorDlpcApi->getLEDCurrent(red, green, blue);
    printf("projector's current light strength: red %f, green %f, blue %f \n", red, green, blue);
    ASSERT_EQ(isSucess, true);
    isSucess = projectorDlpcApi->setLEDCurrent(0.95, 0.95, 0.95);
    ASSERT_EQ(isSucess, true);
    isSucess = projectorDlpcApi->getLEDCurrent(red, green, blue);
    printf("after set light stength, projector's current light strength: red %f, green %f, blue %f \n", red, green, blue);
    isSucess = projectorDlpcApi->disConnect();
    ASSERT_EQ(isSucess, true);
}

如果测试成功,你将看到投影仪按照我们的测试用例顺序,逐一变化投影行为方式。

3. 总结

在这篇博客中,博主介绍了如何编写 C/C++ 用于控制我们的 投影仪 。在下一篇博客中,博主将介绍如何编写 C/C++ 用于控制我们的 结构光3D相机,我们将采用Json文件用于控制我们3D相机的参数,使得每一个Json文件就是一个3D相机

本系列文章将持续更新,如果有等不及想要获得代码的小伙伴,可访问博主Github中的SLMaster项目,动动你的小手指,follow and star⭐!你们的关注是博主持续的动力!

Github:https://github.com/Practice3DVision
QQ群:229441078

公众号:实战3D视觉

在这里插入图片描述

【资源说明】 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 基于C++实现的双目摄像头三维重建源码(相机标定+矫正+获取点云坐标+体积估计)+超详细注释.zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值