LidarView源码分析(十)vtkVelodyneLegacyPacketInterpreter类

纯虚函数

vtkVelodyneLegacyPacketInterpreter的基类是vtkVelodyneBasePacketInterpreter。

需要实现的纯虚函数如下:

 /**
   * @brief ProcessPacket process the data packet to get the current informations
   * @param data raw data packet
   * @param dataLength size of the data packet
   * @param PacketReceptionTime
   */
  virtual void ProcessPacket(unsigned char const * data, unsigned int dataLength) = 0;
 
 
  /**
   * @brief PreProcessPacket is use to construct the frame index and get some corretion
   * or live calibration comming from the data. A warning should be raise in case the calibration
   * information does not match the data (ex: factory field, number of laser, ...)
   * @param data raw data packet
   * @param dataLength size of the data packet
   * @param packetInfo[out] Miscellaneous information about the packet
   */
  virtual bool PreProcessPacket(unsigned char const * data, unsigned int dataLength,
                                fpos_t filePosition = fpos_t(), double packetNetworkTime = 0,
                                std::vector<FrameInformation>* frameCatalog = nullptr) = 0;
 
 
  /**
   * @brief IsLidarPacket check if the given packet is really a lidar packet
   * @param data raw data packet
   * @param dataLength size of the data packet
   */
  virtual bool IsLidarPacket(unsigned char const * data, unsigned int dataLength) = 0;
 
 
  /**
   * @brief GetSensorInformation return information to display to the user
   * @param shortVersion True to have a succinct version of the sensor information
   * @return
   */
  virtual std::string GetSensorInformation(bool shortVersion = false) = 0;
 
 
 /**
   * @brief CreateNewEmptyFrame construct a empty polyData with the right DataArray and allocate some
   * space. No CellArray should be created as it can be create once the frame is ready.
   * @param numberOfPoints indicate the space to allocate @todo change the meaning
   */
  virtual vtkSmartPointer<vtkPolyData> CreateNewEmptyFrame(vtkIdType numberOfPoints, vtkIdType prereservedNumberOfPoints = 0) = 0;
 
 
  /**
   * @brief GetSensorName return the name of the lidar sensor used
   */
  virtual std::string GetSensorName() = 0;

vtkVelodyneLegacyPacketInterpreter

vtkVelodyneLegacyPacketInterpreter是用于解析雷达数据包的具体实现类。该类中实现了解析Velodyne雷达数据包的函数,并将数据累积成完整的一帧数据。解析雷达数据包的函数为ProcessPacket,保存完整一帧数据的函数为SplitFrame。具体的解析过程见下图:

 ProcessPacket

 声明如下:

void ProcessPacket(unsigned char const * data, unsigned int dataLength) override;

该函数接受一个无符号字符数组以及该数组的长度。在该函数内对数组中的内容进行解析,如果数据未满一帧,则保存在this->CurrentFrame中,如果数据已经积累够一帧,则使用SplitFrame将完整的一帧数据存放在this->Frames中,然后将this->CurrentFrame重置,用于下一帧数据的接受。

该函数中还根据数据包中存储的雷达信息进行了不同的处理,保存了不同的信息,包括雷达型号,回波类型,线数等。具体见一下代码:

void vtkVelodyneLegacyPacketInterpreter::ProcessPacket(unsigned char const * data, unsigned int dataLength)
{
  if (!this->IsLidarPacket(data, dataLength))
  {
    return;
  }

  // Cast Generic Packet DataStructure: 12 HDLFiringData Blocks/TimeStamp/Factory Bytes
  // 该方式需要确认data的长度和HDLDataPacket类的长度一致
  // 以及保证数据属性的顺序和HDLDataPacket中变量的声明顺序一直
  // 以及data中的数据和DHLDataPacket在内存中的存储方式一直(同为大端或者同为小端)
  const HDLDataPacket* dataPacket = reinterpret_cast<const HDLDataPacket*>(data);

  // HDL64 Specific
  this->IsHDL64Data |= dataPacket->isHDL64();
  // Accumulate HDL64 Status byte data
  if (IsHDL64Data && this->IsCorrectionFromLiveStream &&
    !this->IsCalibrated)
  {
    this->rollingCalibrationData->appendData(dataPacket->TohTimestamp, dataPacket->factoryField1, dataPacket->factoryField2);
    // 从数据流中获取配置信息
    this->HDL64LoadCorrectionsFromStreamData(this->rollingCalibrationData);
    return;
  }

  // Check once for calibration file consistency
  if (this->ShouldCheckSensor)
  {
    // 数据包中包含了雷达型号信息,判断和配置文件中的是否一直
    // 如果是从数据流中获取的配置信息,则直接返回true
    this->CheckReportedSensorAndCalibrationFileConsistent(dataPacket);
    ShouldCheckSensor = false;
  }

  // Process Time
  this->CurrTimestamp = dataPacket->TohTimestamp;

  // Check if the time has rolled during this packet
  if (1e-6 * static_cast<double>(this->CurrTimestamp) < this->ParserMetaData.FirstPacketDataTime)
  {
    reinterpret_cast<VelodyneSpecificFrameInformation*>
        (this->ParserMetaData.SpecificInformation.get())->NbrOfRollingTime++;
  }
  this->ParserMetaData.FirstPacketDataTime = 1e-6 * static_cast<double>(this->CurrTimestamp);

  const unsigned long long timestamp = this->ComputeTimestamp(this->CurrTimestamp, this->ParserMetaData);

  // Update the rpm computation (by packets)
  // 在SplitFrame中通过RpmCalculator计算了RPM,并保存到this->Rpm中,然后重置了this->RpmCalculator_
  this->RpmCalculator_->AddData(dataPacket->firingData[0].getRotationalPosition(), this->CurrTimestamp);

  // Update the transforms here and then call internal transform
  if (SensorTransform) this->SensorTransform->Update();

  // Get Interpreter State Information
  VelodyneSpecificFrameInformation* velodyneFrameInfo =
      reinterpret_cast<VelodyneSpecificFrameInformation*>(this->ParserMetaData.SpecificInformation.get());

  // Firing Block Skipping Feature (Mid Frame Capture handling)
  int firingDataBlockIdx = velodyneFrameInfo->FiringToSkip;
  velodyneFrameInfo->FiringToSkip = 0;

  // Compute the list of total azimuth advanced during one full firing block
  bool isVLS128 = dataPacket->isVLS128();
  std::vector<int> diffs(HDL_FIRING_PER_PKT - 1);
  for (int i = 0; i < HDL_FIRING_PER_PKT - 1; ++i)
  {
    int localDiff = 0;

    if (!isVLS128)
    {
        localDiff = (36000 + 18000 + dataPacket->firingData[i + 1].getRotationalPosition() -
                      dataPacket->firingData[i].getRotationalPosition()) %
                      36000 - 18000;
    }
    diffs[i] = localDiff;
  }

  if (!IsHDL64Data)
  { // with HDL64, it should be filled by LoadCorrectionsFromStreamData
    this->ReportedSensor = dataPacket->getSensorType();
    this->ReportedSensorReturnMode = dataPacket->getDualReturnSensorMode();
  }

  std::sort(diffs.begin(), diffs.end());
  // Assume the median of the packet's rotationalPosition differences
  int azimuthDiff = diffs[HDL_FIRING_PER_PKT / 2];
  if (this->IsHDL64Data)
  {
    azimuthDiff = diffs[HDL_FIRING_PER_PKT - 2];
  }

  // assert(azimuthDiff > 0);

  // Add DualReturn-specific arrays if newly detected dual return packet
  if (dataPacket->isDualModeReturn() && !this->HasDualReturn)
  {
    this->HasDualReturn = true;
    AddArrayIfNotNull(this->CurrentFrame->GetPointData(), this->DistanceFlag);
    AddArrayIfNotNull(this->CurrentFrame->GetPointData(), this->IntensityFlag);
    AddArrayIfNotNull(this->CurrentFrame->GetPointData(), this->DualReturnMatching);
  }

  for (; firingDataBlockIdx < HDL_FIRING_PER_PKT; ++firingDataBlockIdx)
  {
    const HDLFiringData* firingData = &(dataPacket->firingData[firingDataBlockIdx]);
    const HDLFiringData* extData = NULL;
    // clang-format off
    int multiBlockLaserIdOffset =
        (firingData->blockIdentifier == BLOCK_0_TO_31)  ?  0 :(
        (firingData->blockIdentifier == BLOCK_32_TO_63) ? 32 :(
        (firingData->blockIdentifier == BLOCK_64_TO_95) ? 64 :(
        (firingData->blockIdentifier == BLOCK_96_TO_127)? 96 :(
                                                           0))));
    // clang-format on

    // Skip dummy blocks of VLS-128 dual mode last 4 blocks
    if (isVLS128 && (firingData->blockIdentifier == 0 || firingData->blockIdentifier == 0xFFFF || this->SkipExtDataBlock))
    {
      this->SkipExtDataBlock = false;
      continue;
    }

    if (isVLS128 && (dataPacket->getExtDataPacketType() > EXT_MODE_NONE))
    {
        // For extended data look ahead to every third block
        if (!dataPacket->isDualReturnFiringBlock(firingDataBlockIdx))
        {
            extData = &(dataPacket->firingData[firingDataBlockIdx+2]);
        }
        else
        {
            extData = &(dataPacket->firingData[firingDataBlockIdx+1]);

            // Skip next block as it contains extended data, not firing data
            this->SkipExtDataBlock = true;
        }
    }

    if (this->CurrentFrameState->hasChangedWithValue(*firingData))
    {
      // 如果累积够一帧数据。则进行数据帧拆分。
      // 注意,此时firingData中保存的是下一帧的数据。
      // 只有通过下一帧的数据和当前存储的数据进行比较,才能得出已经够一帧了。
      // 在此处调用SplitFrame,意味这拆分帧在由ProcessPacket函数进行控制
      // 即FramingMethod_t framingMethodAskingForSplitFrame = FramingMethod_t::INTERPRETER_FRAMING
      // 拆分完当前帧后,会重置this->CurrentFrame,用于后续继续向其添加数据。
      this->SplitFrame();
    }

    if (isVLS128)
    {
      azimuthDiff = dataPacket->getRotationalDiffForVLS128(firingDataBlockIdx, LastAzimuth);
      if (dataPacket->isDualModeReturn())
      {
        // Save last azimuth from final block in packet
        if (firingData->blockIdentifier == BLOCK_96_TO_127 && dataPacket->isDualReturnFiringBlock(firingDataBlockIdx))
        {
            this->LastAzimuth = dataPacket->firingData[firingDataBlockIdx].getRotationalPosition();
        }
      }
    }

    // FOV Reduction Feature: Jump Detection > 1 degree
    // WIP to be tested with non-VLS128 DATA, lastazimuth must be saved for both
    if (azimuthDiff * 0.01 > 1)
    {
      azimuthDiff = this->LastAzimuthDiff;
    }else{
      this->LastAzimuthDiff = azimuthDiff;
    }

    // Skip this firing every PointSkip
    if (this->FiringsSkip == 0 || firingDataBlockIdx % (this->FiringsSkip + 1) == 0)
    {
      // 处理数据包中的数据
      this->ProcessFiring(firingData, multiBlockLaserIdOffset, firingDataBlockIdx, azimuthDiff, timestamp,
        this->CurrTimestamp, dataPacket->isDualReturnFiringBlock(firingDataBlockIdx), dataPacket->isDualModeReturn(), extData, dataPacket->getExtDataPacketType());
    }
  }
}

ProcessFiring

ProcessFiring在ProcessPacket中被调用,用来处理数据包中存储的雷达测量数据。一个数据包中包含一些雷达的信息,以及测量数据。

void vtkVelodyneLegacyPacketInterpreter::ProcessFiring(const HDLFiringData *firingData, int multiBlockFiringLaserIdOffset, int firingDataBlockIdx, int azimuthDiff, unsigned long long timestamp, unsigned int rawtime, bool isThisFiringDualReturnData, bool isDualReturnPacket, const HDLFiringData *extData, int extDataPacketType)
{
  // First return block of a dual return packet: init last point of laser
  if (!isThisFiringDualReturnData &&
    (!this->IsHDL64Data || (this->IsHDL64Data && ((firingDataBlockIdx % 4) == 0))))
  {
    this->FirstPointIdOfDualReturnPair = this->Points->GetNumberOfPoints();
  }

  unsigned short firingElevation100th = firingData->getElevation100th();

  for (int dsrBase32 = 0; dsrBase32 < HDL_LASER_PER_FIRING; dsrBase32++)
  {
    const unsigned char channelNumberOr_dsrBase32_forVLP16 = static_cast<unsigned char>(dsrBase32 + multiBlockFiringLaserIdOffset);
    unsigned char channelNumber = channelNumberOr_dsrBase32_forVLP16;
    const unsigned short azimuth = firingData->getRotationalPosition();

    // Detect VLP-16 data and adjust laser id if necessary
    int firingWithinBlock = 0;

    if (this->CalibrationReportedNumLasers == 16)
    {
      if (multiBlockFiringLaserIdOffset != 0)
      {
        if (!this->alreadyWarnedForIgnoredHDL64FiringPacket)
        {
          vtkGenericWarningMacro("Error: Received a HDL-64 UPPERBLOCK firing packet "
                                 "with a VLP-16 calibration file. Ignoring the firing.");
          this->alreadyWarnedForIgnoredHDL64FiringPacket = true;
        }
        return;
      }
      if (channelNumber >= 16)
      {
        channelNumber -= 16;
        firingWithinBlock = 1;
      }
    }

    // 时间插值
    // Interpolate azimuths and timestamps per laser within firing blocks
    double timestampadjustment = 0;
    int azimuthadjustment = 0;
    if (this->UseIntraFiringAdjustment)
    {
      double blockdsr0 = 0, nextblockdsr0 = 1;
      switch (this->CalibrationReportedNumLasers)
      {
        case 128:
        {
          timestampadjustment =
            VLS128AdjustTimeStamp(firingDataBlockIdx, dsrBase32, isDualReturnPacket,
              extDataPacketType, this->VLS128_UseIntraFiringTimingFromOldFWVersions);

          if (isDualReturnPacket)
          {
              // With VLS-128 dual return packets only one dsr0 per packet, so this method will be used to
              // ensure azimuthadjustment is correctly derived below
              if (extDataPacketType > EXT_MODE_NONE)
              {
                nextblockdsr0 = VLS128AdjustTimeStamp(11, 32, isDualReturnPacket, extDataPacketType,
                  this->VLS128_UseIntraFiringTimingFromOldFWVersions);
                blockdsr0 = VLS128AdjustTimeStamp(0, 0, isDualReturnPacket, extDataPacketType,
                  this->VLS128_UseIntraFiringTimingFromOldFWVersions);
              }
              else
              {
                nextblockdsr0 = VLS128AdjustTimeStamp(7, 32, isDualReturnPacket, extDataPacketType,
                  this->VLS128_UseIntraFiringTimingFromOldFWVersions);
                blockdsr0 = VLS128AdjustTimeStamp(0, 0, isDualReturnPacket, extDataPacketType,
                  this->VLS128_UseIntraFiringTimingFromOldFWVersions);
              }
          }
          else
          {
            // dsr0 occurs every fourth block with VLS-128 single return packets
            nextblockdsr0 =
              VLS128AdjustTimeStamp((firingDataBlockIdx / 4) * 4 + 4, 0, isDualReturnPacket,
                extDataPacketType, this->VLS128_UseIntraFiringTimingFromOldFWVersions);
            blockdsr0 = VLS128AdjustTimeStamp((firingDataBlockIdx / 4) * 4, 0, isDualReturnPacket,
              extDataPacketType, this->VLS128_UseIntraFiringTimingFromOldFWVersions);
          }
          break;
        }
        case 64:
        {
          timestampadjustment = -HDL64EAdjustTimeStamp(firingDataBlockIdx, dsrBase32, isDualReturnPacket);
          nextblockdsr0 = -HDL64EAdjustTimeStamp(
            firingDataBlockIdx + (isDualReturnPacket ? 4 : 2), 0, isDualReturnPacket);
          blockdsr0 = -HDL64EAdjustTimeStamp(firingDataBlockIdx, 0, isDualReturnPacket);
          break;
        }
        case 32:
        {
          if (this->ReportedSensor == VLP32AB || this->ReportedSensor == VLP32C)
          {
            timestampadjustment = VLP32AdjustTimeStamp(firingDataBlockIdx, dsrBase32, isDualReturnPacket);
            nextblockdsr0 = VLP32AdjustTimeStamp(
              firingDataBlockIdx + (isDualReturnPacket ? 2 : 1), 0, isDualReturnPacket);
            blockdsr0 = VLP32AdjustTimeStamp(firingDataBlockIdx, 0, isDualReturnPacket);
          }
          else
          {
            timestampadjustment = HDL32AdjustTimeStamp(firingDataBlockIdx, dsrBase32, isDualReturnPacket);
            nextblockdsr0 = HDL32AdjustTimeStamp(
              firingDataBlockIdx + (isDualReturnPacket ? 2 : 1), 0, isDualReturnPacket);
            blockdsr0 = HDL32AdjustTimeStamp(firingDataBlockIdx, 0, isDualReturnPacket);
          }
          break;
        }
        case 16:
        {
          timestampadjustment =
            VLP16AdjustTimeStamp(firingDataBlockIdx, channelNumber, firingWithinBlock, isDualReturnPacket);
          nextblockdsr0 = VLP16AdjustTimeStamp(
            firingDataBlockIdx + (isDualReturnPacket ? 2 : 1), 0, 0, isDualReturnPacket);
          blockdsr0 = VLP16AdjustTimeStamp(firingDataBlockIdx, 0, 0, isDualReturnPacket);
          break;
        }
        default:
        {
          timestampadjustment = 0.0;
          blockdsr0 = 0.0;
          nextblockdsr0 = 1.0;
        }
      }
      azimuthadjustment = vtkMath::Round(
        azimuthDiff * ((timestampadjustment - blockdsr0) / (nextblockdsr0 - blockdsr0)));
      timestampadjustment = vtkMath::Round(timestampadjustment);

    }

    if ((!this->IgnoreZeroDistances || firingData->laserReturns[dsrBase32].distance != 0.0) &&
       static_cast<bool>(this->LaserSelection->GetTuple1(channelNumber)))
    {
      const unsigned short adjustedAzimuth =
        (36000 + (static_cast<int>(azimuth) + azimuthadjustment)) % 36000;
      // 处理一个测量数据。该函数在for循环中,即一个包中包含多个测量数据。
      this->PushFiringData(channelNumber, channelNumberOr_dsrBase32_forVLP16, adjustedAzimuth, firingElevation100th,
        timestamp + static_cast<unsigned long long>(timestampadjustment),
        rawtime + static_cast<unsigned int>(timestampadjustment),
        &(firingData->laserReturns[dsrBase32]),
        isThisFiringDualReturnData, extDataPacketType, &(extData->laserReturns[dsrBase32]));
    }
  }
}

PushFiringData

将一个测量数据转换成点以及其对应的属性,添加到this->CurrentFrame中。类中由一些列指针指向this->CurrentFrame中的数据,将数据加入到对应的属性指针中,即保存到了this->CurrentFrame中。

在将测量值转换成对应的以mi或者角度为单位的物理量后,主要调用了InsertNextValueIfNotNull函数将值添加到对应的数组中。

void vtkVelodyneLegacyPacketInterpreter::PushFiringData(unsigned char channelNumber,
              const unsigned char channelNumberOr_dsrBase32_forVLP16, unsigned short azimuth,
              const unsigned short firingElevation100th, const unsigned long long timestamp,
              const unsigned int rawtime, const HDLLaserReturn* laserReturn,
              const bool isFiringDualReturnData,
              const int extDataPacketType, const HDLLaserReturn* extData)
{
  azimuth %= 36000;
  const vtkIdType thisPointId = this->Points->GetNumberOfPoints();
  // double firingElevation = static_cast<double>(firingElevation100th) / 100.0;

  // Compute raw position
  // 获取测量数据
  bool applyIntensityCorrection =
    this->WantIntensityCorrection && this->IsHDL64Data && !(this->SensorPowerMode == CorrectionOn);

  RawValues rawValues(azimuth, firingElevation100th, laserReturn->distance, laserReturn->intensity);
  CorrectedValues correctedValues; // 保存三维直角坐标系形式的点

  // 将测量数据转换成米或者度的物理量。
  // 该函数在vtkVelodyneBasePacketInterpreter中定义
  this->ComputeCorrectedValues(
      rawValues,
      channelNumber,
      correctedValues,
      applyIntensityCorrection
    );

  double & distanceM = correctedValues.distance; // 距离
  short intensity = correctedValues.intensity;  // 强度
  double (& pos)[3] = correctedValues.position;  // 位置x, y, z

  uint32_t temp = 0;

  // Apply sensor transform
//  cout << "this->SensorTransform" << this->SensorTransform->GetPosition()[0]
// << " " << this->SensorTransform->GetPosition()[0] << " " << this->SensorTransform->GetPosition()[0] << endl;
  if (SensorTransform) this->SensorTransform->InternalTransformPoint(pos, pos);

  // 根据不同的坐标系进行范围滤波,滤掉超出范围的点
  if (this->shouldBeCroppedOut(pos))
    return;

  //ASSUME CONFIDENCE //WIP Triple return mode not implemented
  if (extDataPacketType > EXT_MODE_NONE)
  {
      // First 2 bytes are swapped 0|1|2 -> 1|0|2
      const unsigned char * bytes = reinterpret_cast<const unsigned char*>(extData);
      temp = (static_cast<unsigned int>(bytes[1]) << 16)
           + (static_cast<unsigned int>(bytes[0]) << 8)
           + (static_cast<unsigned int>(bytes[2]) << 0);
      if (isFiringDualReturnData)
      {
        if (this->HideDropPoints && (temp & 0x800000))
        {
          return;
        }
      }
      else
      {
        if (this->HideDropPoints && (temp & 0x800) )
        {
          return;
        }
      }
  }

  // Do not add any data before here as this might short-circuit
  if (isFiringDualReturnData)
  {
    const vtkIdType dualPointId = this->LastPointId[channelNumberOr_dsrBase32_forVLP16]; //Can't be channelNumber because of VLP16 dual mode data layout
    if (dualPointId < this->FirstPointIdOfDualReturnPair)
    {
      // No matching point from first set (skipped?)
      InsertNextValueIfNotNull(this->Flags, DUAL_DOUBLED);
      InsertNextValueIfNotNull(this->DistanceFlag, 0);
      InsertNextValueIfNotNull(this->DualReturnMatching, -1); // std::numeric_limits<vtkIdType>::quiet_NaN()
      InsertNextValueIfNotNull(this->IntensityFlag, 0);
    }
    else
    {
      const short dualIntensity = this->Intensity->GetValue(dualPointId);
      const double dualDistance = this->Distance->GetValue(dualPointId);
      unsigned int firstFlags = this->Flags->GetValue(dualPointId);
      unsigned int secondFlags = 0;

      if (dualDistance == distanceM && intensity == dualIntensity)
      {
        if(this->IgnoreZeroDistances)
        {
          // ignore duplicate point and leave first with original flags
          return;
        }
        // Otherwise we add the duplicate point
      }

      if (dualIntensity < intensity)
      {
        firstFlags &= ~DUAL_INTENSITY_HIGH;
        secondFlags |= DUAL_INTENSITY_HIGH;
      }
      else
      {
        firstFlags &= ~DUAL_INTENSITY_LOW;
        secondFlags |= DUAL_INTENSITY_LOW;
      }

      if (dualDistance < distanceM)
      {
        firstFlags &= ~DUAL_DISTANCE_FAR;
        secondFlags |= DUAL_DISTANCE_FAR;
      }
      else
      {
        firstFlags &= ~DUAL_DISTANCE_NEAR;
        secondFlags |= DUAL_DISTANCE_NEAR;
      }

      // We will output only one point so return out of this
      if (this->DualReturnFilter)
      {
        if (!(secondFlags & this->DualReturnFilter))
        {
          // second return does not match filter; skip
          SetValueIfNotNull(this->Flags, dualPointId, firstFlags);
          SetValueIfNotNull(this->DistanceFlag, dualPointId, MapDistanceFlag(firstFlags));
          SetValueIfNotNull(this->IntensityFlag, dualPointId, MapIntensityFlag(firstFlags));
          return;
        }
        if (!(firstFlags & this->DualReturnFilter))
        {
          // first return does not match filter; replace with second return
          this->Points->SetPoint(dualPointId, pos);
          SetValueIfNotNull(this->Distance, dualPointId, distanceM);
          SetValueIfNotNull(this->DistanceRaw, dualPointId, laserReturn->distance);
          SetValueIfNotNull(this->Intensity, dualPointId, intensity);
          SetValueIfNotNull(this->Timestamp, dualPointId, timestamp);
          SetValueIfNotNull(this->RawTime, dualPointId, rawtime);
          SetValueIfNotNull(this->Flags, dualPointId, secondFlags);
          SetValueIfNotNull(this->DistanceFlag, dualPointId, MapDistanceFlag(secondFlags));
          SetValueIfNotNull(this->IntensityFlag, dualPointId, MapIntensityFlag(secondFlags));
          return;
        }
      }

      SetValueIfNotNull(this->Flags, dualPointId, firstFlags);
      SetValueIfNotNull(this->DistanceFlag, dualPointId, MapDistanceFlag(firstFlags));
      SetValueIfNotNull(this->IntensityFlag, dualPointId, MapIntensityFlag(firstFlags));
      InsertNextValueIfNotNull(this->Flags, secondFlags);
      InsertNextValueIfNotNull(this->DistanceFlag, MapDistanceFlag(secondFlags));
      InsertNextValueIfNotNull(this->IntensityFlag, MapIntensityFlag(secondFlags));
      // The first return indicates the dual return
      // and the dual return indicates the first return
      InsertNextValueIfNotNull(this->DualReturnMatching, dualPointId);
      SetValueIfNotNull(this->DualReturnMatching, dualPointId, thisPointId);
    }
  }
  else
  {
    InsertNextValueIfNotNull(this->Flags, DUAL_DOUBLED);
    InsertNextValueIfNotNull(this->DistanceFlag, 0);
    InsertNextValueIfNotNull(this->IntensityFlag, 0);
    InsertNextValueIfNotNull(this->DualReturnMatching, -1); // std::numeric_limits<vtkIdType>::quiet_NaN()
  }

  // 添加数据
  this->Points->InsertNextPoint(pos);
  InsertNextValueIfNotNull(this->PointsX, pos[0]);
  InsertNextValueIfNotNull(this->PointsY, pos[1]);
  InsertNextValueIfNotNull(this->PointsZ, pos[2]);
  InsertNextValueIfNotNull(this->Azimuth, azimuth);
  InsertNextValueIfNotNull(this->Intensity, intensity);
  InsertNextValueIfNotNull(this->LaserId, channelNumber);
  InsertNextValueIfNotNull(this->Timestamp, timestamp);
  InsertNextValueIfNotNull(this->RawTime, rawtime);
  InsertNextValueIfNotNull(this->Distance, distanceM);
  InsertNextValueIfNotNull(this->DistanceRaw, laserReturn->distance);
  this->LastPointId[channelNumberOr_dsrBase32_forVLP16] = thisPointId;
  InsertNextValueIfNotNull(this->VerticalAngle, correctedValues.elevation);

  //ASSUME CONFIDENCE //WIP Triple return mode not implemented
  if (extDataPacketType > EXT_MODE_NONE)
  {
    if (isFiringDualReturnData)
    { // Second Return
      InsertNextValueIfNotNull(this->BinaryFlags, u32_to_str((temp & 0xFFF000) >> 12));
      InsertNextValueIfNotNull(this->Drop, (temp & 0x800000) >> 23);
      // Reserved >> 22
      InsertNextValueIfNotNull(this->RS, (temp & 0x200000) >> 21);
      InsertNextValueIfNotNull(this->RL, (temp & 0x100000) >> 20);
      InsertNextValueIfNotNull(this->RG, (temp & 0x080000) >> 19);
      InsertNextValueIfNotNull(this->Interference, (temp & 0x060000) >> 17);
      InsertNextValueIfNotNull(this->SunLevel, (temp & 0x018000) >> 15);
      InsertNextValueIfNotNull(this->Confidence, (temp & 0x007000) >> 12);
    }
    else
    { // First Return
      InsertNextValueIfNotNull(this->BinaryFlags, u32_to_str(temp & 0xFFF));
      InsertNextValueIfNotNull(this->Drop, (temp & 0x800) >> 11);
      // Reserved >> 10
      InsertNextValueIfNotNull(this->RS, (temp & 0x200) >> 9);
      InsertNextValueIfNotNull(this->RL, (temp & 0x100) >> 8);
      InsertNextValueIfNotNull(this->RG, (temp & 0x080) >> 7);
      InsertNextValueIfNotNull(this->Interference, (temp & 0x060) >> 5);
      InsertNextValueIfNotNull(this->SunLevel    , (temp & 0x018) >> 3);
      InsertNextValueIfNotNull(this->Confidence  , (temp & 0x007) >> 0);
    }
  }
}

SplitFrame

该函数用于拆分帧,将满足一帧的数据进行保存。

bool vtkVelodyneLegacyPacketInterpreter::SplitFrame(bool force,
                                                    FramingMethod_t framingMethodAskingForSplitFrame)
{
  // 如果对应的数组不为空,则添加到this->CurrentFrame中
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->BinaryFlags);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->Drop);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->Confidence);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->Interference);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->SunLevel);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->RS);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->RL);
  AddArrayIfNotEmpty(this->CurrentFrame->GetPointData(), this->RG);

  // 调用基类中的SplitFrame
  if (this->vtkLidarPacketInterpreter::SplitFrame(force, framingMethodAskingForSplitFrame))
  {
    // 更新针对于该解析器的一些变量,用于下一帧的统计
    for (size_t n = 0; n < HDL_MAX_NUM_LASERS; ++n)
    {
      this->LastPointId[n] = -1;
    }
    // Stats RPM
    this->Rpm = this->RpmCalculator_->GetRPM();
    this->RpmCalculator_->ResetRPM();
    // Stats HZ
    this->Frequency = RpmCalculator_->ComputeFrequency(this->CurrTimestamp);

    return true;
  }

  return false;
}

在vtkVelodyneLegacyPacketInterpreter中的SplitFrame,只是对特定于vtkVelodyneLegacyPacketInterpreter的一些变量进行了设置,然后调用了vtkLidarPacketInterpreter中的SplitFrame,在其中显示添加对this->CurrentFrame中添加了vtkCellArray,不全了vtkPolyData的拓扑数据,然后将当前帧添加到this->Frames,最后使用CreateNewEmptyFrame为this->CurrentFrame创建一个新的空白帧,用于保存下一帧的数据。

bool vtkLidarPacketInterpreter::SplitFrame(bool force, FramingMethod_t framingMethodAskingForSplitFrame)
{
  if ((force || this->FramingMethod == framingMethodAskingForSplitFrame) && this->CurrentFrame)
  {
    const vtkIdType nPtsOfCurrentDataset= this->CurrentFrame->GetNumberOfPoints();
    if (this->IgnoreEmptyFrames && (nPtsOfCurrentDataset == 0) && !force)
    {
      return false;
    }

    // add vertex to the polydata
    this->CurrentFrame->SetVerts(NewVertexCells(this->CurrentFrame->GetNumberOfPoints()));
    // split the frame
    this->Frames.push_back(this->CurrentFrame);
    // create a new frame
    this->CurrentFrame = this->CreateNewEmptyFrame(0, nPtsOfCurrentDataset);

    return true;
  }
  return false;
}

CreateNewEmptyFrame

该函数比较简单,构造了一个空白的vtkPolyData,然后构造一些成员变量指针,将这些指针添加到vtkPolyData中,最后返回vtkPolyData。因为使用指针进行数据传递,可以很方便的使用不同的成员变量访问同一个属性内存。

vtkSmartPointer<vtkPolyData> vtkVelodyneLegacyPacketInterpreter::CreateNewEmptyFrame(vtkIdType numberOfPoints, vtkIdType prereservedNumberOfPoints)
{
  const int defaultPrereservedNumberOfPointsPerFrame = 60000;
  // prereserve for 50% points more than actually received in previous frame
  prereservedNumberOfPoints = std::max(static_cast<int>(prereservedNumberOfPoints * 1.5), defaultPrereservedNumberOfPointsPerFrame);

  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();

  // points
  vtkNew<vtkPoints> points;
  points->SetDataTypeToFloat();
  points->Allocate(prereservedNumberOfPoints);
  if (numberOfPoints > 0 )
  {
    points->SetNumberOfPoints(numberOfPoints);
  }
  points->GetData()->SetName("Points_m_XYZ");
  polyData->SetPoints(points.GetPointer());
//  polyData->SetVerts(NewVertexCells(numberOfPoints));

  // intensity
  this->Points = points.GetPointer();
  InitArrayForPolyData(true,  PointsX, "X", numberOfPoints,
    prereservedNumberOfPoints, polyData, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  PointsY, "Y", numberOfPoints,
    prereservedNumberOfPoints, polyData, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  PointsZ, "Z", numberOfPoints,
    prereservedNumberOfPoints, polyData, this->EnableAdvancedArrays);

  InitArrayForPolyData(false, Intensity, "intensity", numberOfPoints,
    prereservedNumberOfPoints, polyData);
    
  InitArrayForPolyData(true,  BinaryFlags, "binary_flags_string", numberOfPoints,
    prereservedNumberOfPoints, nullptr);
  InitArrayForPolyData(true,  Drop, "drop", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  Confidence, "confidence", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  Interference, "interference", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  SunLevel, "sun_level", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  RS, "retro_shadow", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  RL, "range_limited", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  RG, "retro_ghost", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(false, LaserId, "laser_id", numberOfPoints,
    prereservedNumberOfPoints, polyData);
  InitArrayForPolyData(false, Azimuth, "azimuth", numberOfPoints,
    prereservedNumberOfPoints, polyData);
  InitArrayForPolyData(false, Distance, "distance_m", numberOfPoints,
    prereservedNumberOfPoints, polyData);
  InitArrayForPolyData(true,  DistanceRaw, "distance_raw", numberOfPoints,
    prereservedNumberOfPoints, polyData, this->EnableAdvancedArrays);
  InitArrayForPolyData(false, Timestamp, "adjustedtime", numberOfPoints,
    prereservedNumberOfPoints, polyData);
  InitArrayForPolyData(false, RawTime, "timestamp", numberOfPoints,
    prereservedNumberOfPoints, polyData);
  InitArrayForPolyData(true,  DistanceFlag, "dual_distance", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(true,  IntensityFlag, "dual_intensity", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(false, Flags, "dual_flags", numberOfPoints,
    prereservedNumberOfPoints, nullptr);
  InitArrayForPolyData(true,  DualReturnMatching, "dual_return_matching", numberOfPoints,
    prereservedNumberOfPoints, nullptr, this->EnableAdvancedArrays);
  InitArrayForPolyData(false, VerticalAngle, "vertical_angle", numberOfPoints,
    prereservedNumberOfPoints, polyData);

  if (this->HasDualReturn)
  {
    AddArrayIfNotNull(polyData->GetPointData(), this->DistanceFlag);
    AddArrayIfNotNull(polyData->GetPointData(), this->IntensityFlag);
    AddArrayIfNotNull(polyData->GetPointData(), this->DualReturnMatching);
  }

  // Select array Intensity by default
  polyData->GetPointData()->SetActiveScalars("intensity");

  return polyData;
}

 IsLidarPacket

该函数通过数据长度来判断是否为雷达数据包。除此之外,还可以对data中的数据进行判断,比如校验和。

bool vtkVelodyneLegacyPacketInterpreter::IsLidarPacket(unsigned char const* vtkNotUsed(data), unsigned int dataLength)
{
  if (dataLength == HDLDataPacket::getDataByteLength())
  {
    // Data-Packet Specifications says that laser-packets are 1206 byte long.
    //  That is : (2+2+(2+1)*32)*12 + 4 + 1 + 1
    //                #lasers^   ^#firingPerPkt
    return true;
  }
  return false;
}

GetSensorName

获取雷达名称。使用了vtkDataPacket.h中的宏定义和一个获取名字的函数。

std::string vtkVelodyneLegacyPacketInterpreter::GetSensorName()
{
  return DataPacketFixedLength::SensorTypeToString(this->ReportedSensor);
}
// vtkDataPacket.h
enum SensorType
{
  HDL32E = 0x21,     // decimal: 33
  VLP16 = 0x22,      // decimal: 34
  VLP32AB = 0x23,    // decimal: 35
  VLP16HiRes = 0x24, // decimal: 36
  VLP32C = 0x28,     // decimal: 40

  // Work around : this is not defined by any specification
  // But it is usefull to define
  HDL64 = 0xa0,  // decimal: 160
  VLS128 = 0xa1, // decimal: 161
};

static inline std::string SensorTypeToString(SensorType type)
{
  switch (type)
  {
    case SensorType::HDL32E:
      return "HDL-32E";
    case SensorType::VLP16:
      return "VLP-16";
    case SensorType::VLP32AB:
      return "VLP-32AB";
    case SensorType::VLP16HiRes:
      return "VLP-16 Hi-Res";
    case SensorType::VLP32C:
      return "VLP-32C";
    case SensorType::HDL64:
      return "HDL-64";
    case SensorType::VLS128:
      return "VLS-128";
    default:
      return "Unknown";
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值